netwerk/protocol/http/HttpBaseChannel.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/netwerk/protocol/http/HttpBaseChannel.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2169 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set sw=2 ts=8 et tw=80 : */
     1.6 +
     1.7 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
    1.10 +
    1.11 +// HttpLog.h should generally be included first
    1.12 +#include "HttpLog.h"
    1.13 +
    1.14 +#include "mozilla/net/HttpBaseChannel.h"
    1.15 +
    1.16 +#include "nsHttpHandler.h"
    1.17 +#include "nsMimeTypes.h"
    1.18 +#include "nsNetUtil.h"
    1.19 +
    1.20 +#include "nsICachingChannel.h"
    1.21 +#include "nsIPrincipal.h"
    1.22 +#include "nsISeekableStream.h"
    1.23 +#include "nsITimedChannel.h"
    1.24 +#include "nsIEncodedChannel.h"
    1.25 +#include "nsIApplicationCacheChannel.h"
    1.26 +#include "nsEscape.h"
    1.27 +#include "nsStreamListenerWrapper.h"
    1.28 +#include "nsISecurityConsoleMessage.h"
    1.29 +#include "nsURLHelper.h"
    1.30 +#include "nsICookieService.h"
    1.31 +#include "nsIStreamConverterService.h"
    1.32 +#include "nsCRT.h"
    1.33 +#include "nsContentUtils.h"
    1.34 +#include "nsIScriptSecurityManager.h"
    1.35 +#include "nsIObserverService.h"
    1.36 +
    1.37 +#include <algorithm>
    1.38 +
    1.39 +namespace mozilla {
    1.40 +namespace net {
    1.41 +
    1.42 +HttpBaseChannel::HttpBaseChannel()
    1.43 +  : mStartPos(UINT64_MAX)
    1.44 +  , mStatus(NS_OK)
    1.45 +  , mLoadFlags(LOAD_NORMAL)
    1.46 +  , mCaps(0)
    1.47 +  , mPriority(PRIORITY_NORMAL)
    1.48 +  , mRedirectionLimit(gHttpHandler->RedirectionLimit())
    1.49 +  , mApplyConversion(true)
    1.50 +  , mCanceled(false)
    1.51 +  , mIsPending(false)
    1.52 +  , mWasOpened(false)
    1.53 +  , mRequestObserversCalled(false)
    1.54 +  , mResponseHeadersModified(false)
    1.55 +  , mAllowPipelining(true)
    1.56 +  , mForceAllowThirdPartyCookie(false)
    1.57 +  , mUploadStreamHasHeaders(false)
    1.58 +  , mInheritApplicationCache(true)
    1.59 +  , mChooseApplicationCache(false)
    1.60 +  , mLoadedFromApplicationCache(false)
    1.61 +  , mChannelIsForDownload(false)
    1.62 +  , mTracingEnabled(true)
    1.63 +  , mTimingEnabled(false)
    1.64 +  , mAllowSpdy(true)
    1.65 +  , mLoadAsBlocking(false)
    1.66 +  , mLoadUnblocked(false)
    1.67 +  , mResponseTimeoutEnabled(true)
    1.68 +  , mAllRedirectsSameOrigin(true)
    1.69 +  , mSuspendCount(0)
    1.70 +  , mProxyResolveFlags(0)
    1.71 +  , mContentDispositionHint(UINT32_MAX)
    1.72 +  , mHttpHandler(gHttpHandler)
    1.73 +  , mRedirectCount(0)
    1.74 +  , mProxyURI(nullptr)
    1.75 +{
    1.76 +  LOG(("Creating HttpBaseChannel @%x\n", this));
    1.77 +
    1.78 +  // Subfields of unions cannot be targeted in an initializer list
    1.79 +  mSelfAddr.raw.family = PR_AF_UNSPEC;
    1.80 +  mPeerAddr.raw.family = PR_AF_UNSPEC;
    1.81 +}
    1.82 +
    1.83 +HttpBaseChannel::~HttpBaseChannel()
    1.84 +{
    1.85 +  LOG(("Destroying HttpBaseChannel @%x\n", this));
    1.86 +
    1.87 +  // Make sure we don't leak
    1.88 +  CleanRedirectCacheChainIfNecessary();
    1.89 +}
    1.90 +
    1.91 +nsresult
    1.92 +HttpBaseChannel::Init(nsIURI *aURI,
    1.93 +                      uint32_t aCaps,
    1.94 +                      nsProxyInfo *aProxyInfo,
    1.95 +                      uint32_t aProxyResolveFlags,
    1.96 +                      nsIURI *aProxyURI)
    1.97 +{
    1.98 +  LOG(("HttpBaseChannel::Init [this=%p]\n", this));
    1.99 +
   1.100 +  NS_PRECONDITION(aURI, "null uri");
   1.101 +
   1.102 +  mURI = aURI;
   1.103 +  mOriginalURI = aURI;
   1.104 +  mDocumentURI = nullptr;
   1.105 +  mCaps = aCaps;
   1.106 +  mProxyResolveFlags = aProxyResolveFlags;
   1.107 +  mProxyURI = aProxyURI;
   1.108 +
   1.109 +  // Construct connection info object
   1.110 +  nsAutoCString host;
   1.111 +  int32_t port = -1;
   1.112 +  bool usingSSL = false;
   1.113 +
   1.114 +  nsresult rv = mURI->SchemeIs("https", &usingSSL);
   1.115 +  if (NS_FAILED(rv)) return rv;
   1.116 +
   1.117 +  rv = mURI->GetAsciiHost(host);
   1.118 +  if (NS_FAILED(rv)) return rv;
   1.119 +
   1.120 +  // Reject the URL if it doesn't specify a host
   1.121 +  if (host.IsEmpty())
   1.122 +    return NS_ERROR_MALFORMED_URI;
   1.123 +
   1.124 +  rv = mURI->GetPort(&port);
   1.125 +  if (NS_FAILED(rv)) return rv;
   1.126 +
   1.127 +  LOG(("host=%s port=%d\n", host.get(), port));
   1.128 +
   1.129 +  rv = mURI->GetAsciiSpec(mSpec);
   1.130 +  if (NS_FAILED(rv)) return rv;
   1.131 +  LOG(("uri=%s\n", mSpec.get()));
   1.132 +
   1.133 +  // Assert default request method
   1.134 +  MOZ_ASSERT(mRequestHead.EqualsMethod(nsHttpRequestHead::kMethod_Get));
   1.135 +
   1.136 +  // Set request headers
   1.137 +  nsAutoCString hostLine;
   1.138 +  rv = nsHttpHandler::GenerateHostPort(host, port, hostLine);
   1.139 +  if (NS_FAILED(rv)) return rv;
   1.140 +
   1.141 +  rv = mRequestHead.SetHeader(nsHttp::Host, hostLine);
   1.142 +  if (NS_FAILED(rv)) return rv;
   1.143 +
   1.144 +  rv = gHttpHandler->AddStandardRequestHeaders(&mRequestHead.Headers());
   1.145 +  if (NS_FAILED(rv)) return rv;
   1.146 +
   1.147 +  nsAutoCString type;
   1.148 +  if (aProxyInfo && NS_SUCCEEDED(aProxyInfo->GetType(type)) &&
   1.149 +      !type.EqualsLiteral("unknown"))
   1.150 +    mProxyInfo = aProxyInfo;
   1.151 +
   1.152 +  return rv;
   1.153 +}
   1.154 +
   1.155 +//-----------------------------------------------------------------------------
   1.156 +// HttpBaseChannel::nsISupports
   1.157 +//-----------------------------------------------------------------------------
   1.158 +
   1.159 +NS_IMPL_ADDREF(HttpBaseChannel)
   1.160 +NS_IMPL_RELEASE(HttpBaseChannel)
   1.161 +
   1.162 +NS_INTERFACE_MAP_BEGIN(HttpBaseChannel)
   1.163 +  NS_INTERFACE_MAP_ENTRY(nsIRequest)
   1.164 +  NS_INTERFACE_MAP_ENTRY(nsIChannel)
   1.165 +  NS_INTERFACE_MAP_ENTRY(nsIEncodedChannel)
   1.166 +  NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
   1.167 +  NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
   1.168 +  NS_INTERFACE_MAP_ENTRY(nsIUploadChannel)
   1.169 +  NS_INTERFACE_MAP_ENTRY(nsIUploadChannel2)
   1.170 +  NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
   1.171 +  NS_INTERFACE_MAP_ENTRY(nsITraceableChannel)
   1.172 +  NS_INTERFACE_MAP_ENTRY(nsIPrivateBrowsingChannel)
   1.173 +  NS_INTERFACE_MAP_ENTRY(nsITimedChannel)
   1.174 +NS_INTERFACE_MAP_END_INHERITING(nsHashPropertyBag)
   1.175 +
   1.176 +//-----------------------------------------------------------------------------
   1.177 +// HttpBaseChannel::nsIRequest
   1.178 +//-----------------------------------------------------------------------------
   1.179 +
   1.180 +NS_IMETHODIMP
   1.181 +HttpBaseChannel::GetName(nsACString& aName)
   1.182 +{
   1.183 +  aName = mSpec;
   1.184 +  return NS_OK;
   1.185 +}
   1.186 +
   1.187 +NS_IMETHODIMP
   1.188 +HttpBaseChannel::IsPending(bool *aIsPending)
   1.189 +{
   1.190 +  NS_ENSURE_ARG_POINTER(aIsPending);
   1.191 +  *aIsPending = mIsPending;
   1.192 +  return NS_OK;
   1.193 +}
   1.194 +
   1.195 +NS_IMETHODIMP
   1.196 +HttpBaseChannel::GetStatus(nsresult *aStatus)
   1.197 +{
   1.198 +  NS_ENSURE_ARG_POINTER(aStatus);
   1.199 +  *aStatus = mStatus;
   1.200 +  return NS_OK;
   1.201 +}
   1.202 +
   1.203 +NS_IMETHODIMP
   1.204 +HttpBaseChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
   1.205 +{
   1.206 +  NS_ENSURE_ARG_POINTER(aLoadGroup);
   1.207 +  *aLoadGroup = mLoadGroup;
   1.208 +  NS_IF_ADDREF(*aLoadGroup);
   1.209 +  return NS_OK;
   1.210 +}
   1.211 +
   1.212 +NS_IMETHODIMP
   1.213 +HttpBaseChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
   1.214 +{
   1.215 +  MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread.");
   1.216 +  
   1.217 +  if (!CanSetLoadGroup(aLoadGroup)) {
   1.218 +    return NS_ERROR_FAILURE;
   1.219 +  }
   1.220 +
   1.221 +  mLoadGroup = aLoadGroup;
   1.222 +  mProgressSink = nullptr;
   1.223 +  mPrivateBrowsing = NS_UsePrivateBrowsing(this);
   1.224 +  return NS_OK;
   1.225 +}
   1.226 +
   1.227 +NS_IMETHODIMP
   1.228 +HttpBaseChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
   1.229 +{
   1.230 +  NS_ENSURE_ARG_POINTER(aLoadFlags);
   1.231 +  *aLoadFlags = mLoadFlags;
   1.232 +  return NS_OK;
   1.233 +}
   1.234 +
   1.235 +NS_IMETHODIMP
   1.236 +HttpBaseChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
   1.237 +{
   1.238 +  mLoadFlags = aLoadFlags;
   1.239 +  return NS_OK;
   1.240 +}
   1.241 +
   1.242 +//-----------------------------------------------------------------------------
   1.243 +// HttpBaseChannel::nsIChannel
   1.244 +//-----------------------------------------------------------------------------
   1.245 +
   1.246 +NS_IMETHODIMP
   1.247 +HttpBaseChannel::GetOriginalURI(nsIURI **aOriginalURI)
   1.248 +{
   1.249 +  NS_ENSURE_ARG_POINTER(aOriginalURI);
   1.250 +  *aOriginalURI = mOriginalURI;
   1.251 +  NS_ADDREF(*aOriginalURI);
   1.252 +  return NS_OK;
   1.253 +}
   1.254 +
   1.255 +NS_IMETHODIMP
   1.256 +HttpBaseChannel::SetOriginalURI(nsIURI *aOriginalURI)
   1.257 +{
   1.258 +  ENSURE_CALLED_BEFORE_CONNECT();
   1.259 +
   1.260 +  NS_ENSURE_ARG_POINTER(aOriginalURI);
   1.261 +  mOriginalURI = aOriginalURI;
   1.262 +  return NS_OK;
   1.263 +}
   1.264 +
   1.265 +NS_IMETHODIMP
   1.266 +HttpBaseChannel::GetURI(nsIURI **aURI)
   1.267 +{
   1.268 +  NS_ENSURE_ARG_POINTER(aURI);
   1.269 +  *aURI = mURI;
   1.270 +  NS_ADDREF(*aURI);
   1.271 +  return NS_OK;
   1.272 +}
   1.273 +
   1.274 +NS_IMETHODIMP
   1.275 +HttpBaseChannel::GetOwner(nsISupports **aOwner)
   1.276 +{
   1.277 +  NS_ENSURE_ARG_POINTER(aOwner);
   1.278 +  *aOwner = mOwner;
   1.279 +  NS_IF_ADDREF(*aOwner);
   1.280 +  return NS_OK;
   1.281 +}
   1.282 +
   1.283 +NS_IMETHODIMP
   1.284 +HttpBaseChannel::SetOwner(nsISupports *aOwner)
   1.285 +{
   1.286 +  mOwner = aOwner;
   1.287 +  return NS_OK;
   1.288 +}
   1.289 +
   1.290 +NS_IMETHODIMP
   1.291 +HttpBaseChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks)
   1.292 +{
   1.293 +  *aCallbacks = mCallbacks;
   1.294 +  NS_IF_ADDREF(*aCallbacks);
   1.295 +  return NS_OK;
   1.296 +}
   1.297 +
   1.298 +NS_IMETHODIMP
   1.299 +HttpBaseChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
   1.300 +{
   1.301 +  MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread.");
   1.302 +  
   1.303 +  if (!CanSetCallbacks(aCallbacks)) {
   1.304 +    return NS_ERROR_FAILURE;
   1.305 +  }
   1.306 +
   1.307 +  mCallbacks = aCallbacks;
   1.308 +  mProgressSink = nullptr;
   1.309 +
   1.310 +  mPrivateBrowsing = NS_UsePrivateBrowsing(this);
   1.311 +  return NS_OK;
   1.312 +}
   1.313 +
   1.314 +NS_IMETHODIMP
   1.315 +HttpBaseChannel::GetContentType(nsACString& aContentType)
   1.316 +{
   1.317 +  if (!mResponseHead) {
   1.318 +    aContentType.Truncate();
   1.319 +    return NS_ERROR_NOT_AVAILABLE;
   1.320 +  }
   1.321 +
   1.322 +  if (!mResponseHead->ContentType().IsEmpty()) {
   1.323 +    aContentType = mResponseHead->ContentType();
   1.324 +    return NS_OK;
   1.325 +  }
   1.326 +
   1.327 +  aContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
   1.328 +  return NS_OK;
   1.329 +}
   1.330 +
   1.331 +NS_IMETHODIMP
   1.332 +HttpBaseChannel::SetContentType(const nsACString& aContentType)
   1.333 +{
   1.334 +  if (mListener || mWasOpened) {
   1.335 +    if (!mResponseHead)
   1.336 +      return NS_ERROR_NOT_AVAILABLE;
   1.337 +
   1.338 +    nsAutoCString contentTypeBuf, charsetBuf;
   1.339 +    bool hadCharset;
   1.340 +    net_ParseContentType(aContentType, contentTypeBuf, charsetBuf, &hadCharset);
   1.341 +
   1.342 +    mResponseHead->SetContentType(contentTypeBuf);
   1.343 +
   1.344 +    // take care not to stomp on an existing charset
   1.345 +    if (hadCharset)
   1.346 +      mResponseHead->SetContentCharset(charsetBuf);
   1.347 +
   1.348 +  } else {
   1.349 +    // We are being given a content-type hint.
   1.350 +    bool dummy;
   1.351 +    net_ParseContentType(aContentType, mContentTypeHint, mContentCharsetHint,
   1.352 +                         &dummy);
   1.353 +  }
   1.354 +
   1.355 +  return NS_OK;
   1.356 +}
   1.357 +
   1.358 +NS_IMETHODIMP
   1.359 +HttpBaseChannel::GetContentCharset(nsACString& aContentCharset)
   1.360 +{
   1.361 +  if (!mResponseHead)
   1.362 +    return NS_ERROR_NOT_AVAILABLE;
   1.363 +
   1.364 +  aContentCharset = mResponseHead->ContentCharset();
   1.365 +  return NS_OK;
   1.366 +}
   1.367 +
   1.368 +NS_IMETHODIMP
   1.369 +HttpBaseChannel::SetContentCharset(const nsACString& aContentCharset)
   1.370 +{
   1.371 +  if (mListener) {
   1.372 +    if (!mResponseHead)
   1.373 +      return NS_ERROR_NOT_AVAILABLE;
   1.374 +
   1.375 +    mResponseHead->SetContentCharset(aContentCharset);
   1.376 +  } else {
   1.377 +    // Charset hint
   1.378 +    mContentCharsetHint = aContentCharset;
   1.379 +  }
   1.380 +  return NS_OK;
   1.381 +}
   1.382 +
   1.383 +NS_IMETHODIMP
   1.384 +HttpBaseChannel::GetContentDisposition(uint32_t *aContentDisposition)
   1.385 +{
   1.386 +  nsresult rv;
   1.387 +  nsCString header;
   1.388 +
   1.389 +  rv = GetContentDispositionHeader(header);
   1.390 +  if (NS_FAILED(rv)) {
   1.391 +    if (mContentDispositionHint == UINT32_MAX)
   1.392 +      return rv;
   1.393 +
   1.394 +    *aContentDisposition = mContentDispositionHint;
   1.395 +    return NS_OK;
   1.396 +  }
   1.397 +
   1.398 +  *aContentDisposition = NS_GetContentDispositionFromHeader(header, this);
   1.399 +  return NS_OK;
   1.400 +}
   1.401 +
   1.402 +NS_IMETHODIMP
   1.403 +HttpBaseChannel::SetContentDisposition(uint32_t aContentDisposition)
   1.404 +{
   1.405 +  mContentDispositionHint = aContentDisposition;
   1.406 +  return NS_OK;
   1.407 +}
   1.408 +
   1.409 +NS_IMETHODIMP
   1.410 +HttpBaseChannel::GetContentDispositionFilename(nsAString& aContentDispositionFilename)
   1.411 +{
   1.412 +  aContentDispositionFilename.Truncate();
   1.413 +  nsresult rv;
   1.414 +  nsCString header;
   1.415 +
   1.416 +  rv = GetContentDispositionHeader(header);
   1.417 +  if (NS_FAILED(rv)) {
   1.418 +    if (!mContentDispositionFilename)
   1.419 +      return rv;
   1.420 +
   1.421 +    aContentDispositionFilename = *mContentDispositionFilename;
   1.422 +    return NS_OK;
   1.423 +  }
   1.424 +
   1.425 +  return NS_GetFilenameFromDisposition(aContentDispositionFilename,
   1.426 +                                       header, mURI);
   1.427 +}
   1.428 +
   1.429 +NS_IMETHODIMP
   1.430 +HttpBaseChannel::SetContentDispositionFilename(const nsAString& aContentDispositionFilename)
   1.431 +{
   1.432 +  mContentDispositionFilename = new nsString(aContentDispositionFilename);
   1.433 +  return NS_OK;
   1.434 +}
   1.435 +
   1.436 +NS_IMETHODIMP
   1.437 +HttpBaseChannel::GetContentDispositionHeader(nsACString& aContentDispositionHeader)
   1.438 +{
   1.439 +  if (!mResponseHead)
   1.440 +    return NS_ERROR_NOT_AVAILABLE;
   1.441 +
   1.442 +  nsresult rv = mResponseHead->GetHeader(nsHttp::Content_Disposition,
   1.443 +                                         aContentDispositionHeader);
   1.444 +  if (NS_FAILED(rv) || aContentDispositionHeader.IsEmpty())
   1.445 +    return NS_ERROR_NOT_AVAILABLE;
   1.446 +
   1.447 +  return NS_OK;
   1.448 +}
   1.449 +
   1.450 +NS_IMETHODIMP
   1.451 +HttpBaseChannel::GetContentLength(int64_t *aContentLength)
   1.452 +{
   1.453 +  NS_ENSURE_ARG_POINTER(aContentLength);
   1.454 +
   1.455 +  if (!mResponseHead)
   1.456 +    return NS_ERROR_NOT_AVAILABLE;
   1.457 +
   1.458 +  *aContentLength = mResponseHead->ContentLength();
   1.459 +  return NS_OK;
   1.460 +}
   1.461 +
   1.462 +NS_IMETHODIMP
   1.463 +HttpBaseChannel::SetContentLength(int64_t value)
   1.464 +{
   1.465 +  NS_NOTYETIMPLEMENTED("HttpBaseChannel::SetContentLength");
   1.466 +  return NS_ERROR_NOT_IMPLEMENTED;
   1.467 +}
   1.468 +
   1.469 +NS_IMETHODIMP
   1.470 +HttpBaseChannel::Open(nsIInputStream **aResult)
   1.471 +{
   1.472 +  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS);
   1.473 +  return NS_ImplementChannelOpen(this, aResult);
   1.474 +}
   1.475 +
   1.476 +//-----------------------------------------------------------------------------
   1.477 +// HttpBaseChannel::nsIUploadChannel
   1.478 +//-----------------------------------------------------------------------------
   1.479 +
   1.480 +NS_IMETHODIMP
   1.481 +HttpBaseChannel::GetUploadStream(nsIInputStream **stream)
   1.482 +{
   1.483 +  NS_ENSURE_ARG_POINTER(stream);
   1.484 +  *stream = mUploadStream;
   1.485 +  NS_IF_ADDREF(*stream);
   1.486 +  return NS_OK;
   1.487 +}
   1.488 +
   1.489 +NS_IMETHODIMP
   1.490 +HttpBaseChannel::SetUploadStream(nsIInputStream *stream,
   1.491 +                               const nsACString &contentType,
   1.492 +                               int64_t contentLength)
   1.493 +{
   1.494 +  // NOTE: for backwards compatibility and for compatibility with old style
   1.495 +  // plugins, |stream| may include headers, specifically Content-Type and
   1.496 +  // Content-Length headers.  in this case, |contentType| and |contentLength|
   1.497 +  // would be unspecified.  this is traditionally the case of a POST request,
   1.498 +  // and so we select POST as the request method if contentType and
   1.499 +  // contentLength are unspecified.
   1.500 +
   1.501 +  if (stream) {
   1.502 +    nsAutoCString method;
   1.503 +    bool hasHeaders;
   1.504 +
   1.505 +    if (contentType.IsEmpty()) {
   1.506 +      method = NS_LITERAL_CSTRING("POST");
   1.507 +      hasHeaders = true;
   1.508 +    } else {
   1.509 +      method = NS_LITERAL_CSTRING("PUT");
   1.510 +      hasHeaders = false;
   1.511 +    }
   1.512 +    return ExplicitSetUploadStream(stream, contentType, contentLength,
   1.513 +                                   method, hasHeaders);
   1.514 +  }
   1.515 +
   1.516 +  // if stream is null, ExplicitSetUploadStream returns error.
   1.517 +  // So we need special case for GET method.
   1.518 +  mUploadStreamHasHeaders = false;
   1.519 +  mRequestHead.SetMethod(NS_LITERAL_CSTRING("GET")); // revert to GET request
   1.520 +  mUploadStream = stream;
   1.521 +  return NS_OK;
   1.522 +}
   1.523 +
   1.524 +//-----------------------------------------------------------------------------
   1.525 +// HttpBaseChannel::nsIUploadChannel2
   1.526 +//-----------------------------------------------------------------------------
   1.527 +
   1.528 +NS_IMETHODIMP
   1.529 +HttpBaseChannel::ExplicitSetUploadStream(nsIInputStream *aStream,
   1.530 +                                       const nsACString &aContentType,
   1.531 +                                       int64_t aContentLength,
   1.532 +                                       const nsACString &aMethod,
   1.533 +                                       bool aStreamHasHeaders)
   1.534 +{
   1.535 +  // Ensure stream is set and method is valid
   1.536 +  NS_ENSURE_TRUE(aStream, NS_ERROR_FAILURE);
   1.537 +
   1.538 +  if (aContentLength < 0 && !aStreamHasHeaders) {
   1.539 +    nsresult rv = aStream->Available(reinterpret_cast<uint64_t*>(&aContentLength));
   1.540 +    if (NS_FAILED(rv) || aContentLength < 0) {
   1.541 +      NS_ERROR("unable to determine content length");
   1.542 +      return NS_ERROR_FAILURE;
   1.543 +    }
   1.544 +  }
   1.545 +
   1.546 +  nsresult rv = SetRequestMethod(aMethod);
   1.547 +  NS_ENSURE_SUCCESS(rv, rv);
   1.548 +
   1.549 +  if (!aStreamHasHeaders) {
   1.550 +    // SetRequestHeader propagates headers to chrome if HttpChannelChild
   1.551 +    nsAutoCString contentLengthStr;
   1.552 +    contentLengthStr.AppendInt(aContentLength);
   1.553 +    SetRequestHeader(NS_LITERAL_CSTRING("Content-Length"), contentLengthStr,
   1.554 +                     false);
   1.555 +    SetRequestHeader(NS_LITERAL_CSTRING("Content-Type"), aContentType,
   1.556 +                     false);
   1.557 +  }
   1.558 +
   1.559 +  mUploadStreamHasHeaders = aStreamHasHeaders;
   1.560 +  mUploadStream = aStream;
   1.561 +  return NS_OK;
   1.562 +}
   1.563 +
   1.564 +NS_IMETHODIMP
   1.565 +HttpBaseChannel::GetUploadStreamHasHeaders(bool *hasHeaders)
   1.566 +{
   1.567 +  NS_ENSURE_ARG(hasHeaders);
   1.568 +
   1.569 +  *hasHeaders = mUploadStreamHasHeaders;
   1.570 +  return NS_OK;
   1.571 +}
   1.572 +
   1.573 +//-----------------------------------------------------------------------------
   1.574 +// HttpBaseChannel::nsIEncodedChannel
   1.575 +//-----------------------------------------------------------------------------
   1.576 +
   1.577 +NS_IMETHODIMP
   1.578 +HttpBaseChannel::GetApplyConversion(bool *value)
   1.579 +{
   1.580 +  *value = mApplyConversion;
   1.581 +  return NS_OK;
   1.582 +}
   1.583 +
   1.584 +NS_IMETHODIMP
   1.585 +HttpBaseChannel::SetApplyConversion(bool value)
   1.586 +{
   1.587 +  LOG(("HttpBaseChannel::SetApplyConversion [this=%p value=%d]\n", this, value));
   1.588 +  mApplyConversion = value;
   1.589 +  return NS_OK;
   1.590 +}
   1.591 +
   1.592 +nsresult
   1.593 +HttpBaseChannel::ApplyContentConversions()
   1.594 +{
   1.595 +  if (!mResponseHead)
   1.596 +    return NS_OK;
   1.597 +
   1.598 +  LOG(("HttpBaseChannel::ApplyContentConversions [this=%p]\n", this));
   1.599 +
   1.600 +  if (!mApplyConversion) {
   1.601 +    LOG(("not applying conversion per mApplyConversion\n"));
   1.602 +    return NS_OK;
   1.603 +  }
   1.604 +
   1.605 +  nsAutoCString contentEncoding;
   1.606 +  char *cePtr, *val;
   1.607 +  nsresult rv;
   1.608 +
   1.609 +  rv = mResponseHead->GetHeader(nsHttp::Content_Encoding, contentEncoding);
   1.610 +  if (NS_FAILED(rv) || contentEncoding.IsEmpty())
   1.611 +    return NS_OK;
   1.612 +
   1.613 +  // The encodings are listed in the order they were applied
   1.614 +  // (see rfc 2616 section 14.11), so they need to removed in reverse
   1.615 +  // order. This is accomplished because the converter chain ends up
   1.616 +  // being a stack with the last converter created being the first one
   1.617 +  // to accept the raw network data.
   1.618 +
   1.619 +  cePtr = contentEncoding.BeginWriting();
   1.620 +  uint32_t count = 0;
   1.621 +  while ((val = nsCRT::strtok(cePtr, HTTP_LWS ",", &cePtr))) {
   1.622 +    if (++count > 16) {
   1.623 +      // That's ridiculous. We only understand 2 different ones :)
   1.624 +      // but for compatibility with old code, we will just carry on without
   1.625 +      // removing the encodings
   1.626 +      LOG(("Too many Content-Encodings. Ignoring remainder.\n"));
   1.627 +      break;
   1.628 +    }
   1.629 +
   1.630 +    if (gHttpHandler->IsAcceptableEncoding(val)) {
   1.631 +      nsCOMPtr<nsIStreamConverterService> serv;
   1.632 +      rv = gHttpHandler->GetStreamConverterService(getter_AddRefs(serv));
   1.633 +
   1.634 +      // we won't fail to load the page just because we couldn't load the
   1.635 +      // stream converter service.. carry on..
   1.636 +      if (NS_FAILED(rv)) {
   1.637 +        if (val)
   1.638 +          LOG(("Unknown content encoding '%s', ignoring\n", val));
   1.639 +        continue;
   1.640 +      }
   1.641 +
   1.642 +      nsCOMPtr<nsIStreamListener> converter;
   1.643 +      nsAutoCString from(val);
   1.644 +      ToLowerCase(from);
   1.645 +      rv = serv->AsyncConvertData(from.get(),
   1.646 +                                  "uncompressed",
   1.647 +                                  mListener,
   1.648 +                                  mListenerContext,
   1.649 +                                  getter_AddRefs(converter));
   1.650 +      if (NS_FAILED(rv)) {
   1.651 +        LOG(("Unexpected failure of AsyncConvertData %s\n", val));
   1.652 +        return rv;
   1.653 +      }
   1.654 +
   1.655 +      LOG(("converter removed '%s' content-encoding\n", val));
   1.656 +      mListener = converter;
   1.657 +    }
   1.658 +    else {
   1.659 +      if (val)
   1.660 +        LOG(("Unknown content encoding '%s', ignoring\n", val));
   1.661 +    }
   1.662 +  }
   1.663 +
   1.664 +  return NS_OK;
   1.665 +}
   1.666 +
   1.667 +NS_IMETHODIMP
   1.668 +HttpBaseChannel::GetContentEncodings(nsIUTF8StringEnumerator** aEncodings)
   1.669 +{
   1.670 +  if (!mResponseHead) {
   1.671 +    *aEncodings = nullptr;
   1.672 +    return NS_OK;
   1.673 +  }
   1.674 +
   1.675 +  const char *encoding = mResponseHead->PeekHeader(nsHttp::Content_Encoding);
   1.676 +  if (!encoding) {
   1.677 +    *aEncodings = nullptr;
   1.678 +    return NS_OK;
   1.679 +  }
   1.680 +  nsContentEncodings* enumerator = new nsContentEncodings(this, encoding);
   1.681 +  NS_ADDREF(*aEncodings = enumerator);
   1.682 +  return NS_OK;
   1.683 +}
   1.684 +
   1.685 +//-----------------------------------------------------------------------------
   1.686 +// HttpBaseChannel::nsContentEncodings <public>
   1.687 +//-----------------------------------------------------------------------------
   1.688 +
   1.689 +HttpBaseChannel::nsContentEncodings::nsContentEncodings(nsIHttpChannel* aChannel,
   1.690 +                                                        const char* aEncodingHeader)
   1.691 +  : mEncodingHeader(aEncodingHeader)
   1.692 +  , mChannel(aChannel)
   1.693 +  , mReady(false)
   1.694 +{
   1.695 +  mCurEnd = aEncodingHeader + strlen(aEncodingHeader);
   1.696 +  mCurStart = mCurEnd;
   1.697 +}
   1.698 +
   1.699 +HttpBaseChannel::nsContentEncodings::~nsContentEncodings()
   1.700 +{
   1.701 +}
   1.702 +
   1.703 +//-----------------------------------------------------------------------------
   1.704 +// HttpBaseChannel::nsContentEncodings::nsISimpleEnumerator
   1.705 +//-----------------------------------------------------------------------------
   1.706 +
   1.707 +NS_IMETHODIMP
   1.708 +HttpBaseChannel::nsContentEncodings::HasMore(bool* aMoreEncodings)
   1.709 +{
   1.710 +  if (mReady) {
   1.711 +    *aMoreEncodings = true;
   1.712 +    return NS_OK;
   1.713 +  }
   1.714 +
   1.715 +  nsresult rv = PrepareForNext();
   1.716 +  *aMoreEncodings = NS_SUCCEEDED(rv);
   1.717 +  return NS_OK;
   1.718 +}
   1.719 +
   1.720 +NS_IMETHODIMP
   1.721 +HttpBaseChannel::nsContentEncodings::GetNext(nsACString& aNextEncoding)
   1.722 +{
   1.723 +  aNextEncoding.Truncate();
   1.724 +  if (!mReady) {
   1.725 +    nsresult rv = PrepareForNext();
   1.726 +    if (NS_FAILED(rv)) {
   1.727 +      return NS_ERROR_FAILURE;
   1.728 +    }
   1.729 +  }
   1.730 +
   1.731 +  const nsACString & encoding = Substring(mCurStart, mCurEnd);
   1.732 +
   1.733 +  nsACString::const_iterator start, end;
   1.734 +  encoding.BeginReading(start);
   1.735 +  encoding.EndReading(end);
   1.736 +
   1.737 +  bool haveType = false;
   1.738 +  if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("gzip"), start, end)) {
   1.739 +    aNextEncoding.AssignLiteral(APPLICATION_GZIP);
   1.740 +    haveType = true;
   1.741 +  }
   1.742 +
   1.743 +  if (!haveType) {
   1.744 +    encoding.BeginReading(start);
   1.745 +    if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("compress"), start, end)) {
   1.746 +      aNextEncoding.AssignLiteral(APPLICATION_COMPRESS);
   1.747 +      haveType = true;
   1.748 +    }
   1.749 +  }
   1.750 +
   1.751 +  if (!haveType) {
   1.752 +    encoding.BeginReading(start);
   1.753 +    if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("deflate"), start, end)) {
   1.754 +      aNextEncoding.AssignLiteral(APPLICATION_ZIP);
   1.755 +      haveType = true;
   1.756 +    }
   1.757 +  }
   1.758 +
   1.759 +  // Prepare to fetch the next encoding
   1.760 +  mCurEnd = mCurStart;
   1.761 +  mReady = false;
   1.762 +
   1.763 +  if (haveType)
   1.764 +    return NS_OK;
   1.765 +
   1.766 +  NS_WARNING("Unknown encoding type");
   1.767 +  return NS_ERROR_FAILURE;
   1.768 +}
   1.769 +
   1.770 +//-----------------------------------------------------------------------------
   1.771 +// HttpBaseChannel::nsContentEncodings::nsISupports
   1.772 +//-----------------------------------------------------------------------------
   1.773 +
   1.774 +NS_IMPL_ISUPPORTS(HttpBaseChannel::nsContentEncodings, nsIUTF8StringEnumerator)
   1.775 +
   1.776 +//-----------------------------------------------------------------------------
   1.777 +// HttpBaseChannel::nsContentEncodings <private>
   1.778 +//-----------------------------------------------------------------------------
   1.779 +
   1.780 +nsresult
   1.781 +HttpBaseChannel::nsContentEncodings::PrepareForNext(void)
   1.782 +{
   1.783 +  MOZ_ASSERT(mCurStart == mCurEnd, "Indeterminate state");
   1.784 +
   1.785 +  // At this point both mCurStart and mCurEnd point to somewhere
   1.786 +  // past the end of the next thing we want to return
   1.787 +
   1.788 +  while (mCurEnd != mEncodingHeader) {
   1.789 +    --mCurEnd;
   1.790 +    if (*mCurEnd != ',' && !nsCRT::IsAsciiSpace(*mCurEnd))
   1.791 +      break;
   1.792 +  }
   1.793 +  if (mCurEnd == mEncodingHeader)
   1.794 +    return NS_ERROR_NOT_AVAILABLE; // no more encodings
   1.795 +  ++mCurEnd;
   1.796 +
   1.797 +  // At this point mCurEnd points to the first char _after_ the
   1.798 +  // header we want.  Furthermore, mCurEnd - 1 != mEncodingHeader
   1.799 +
   1.800 +  mCurStart = mCurEnd - 1;
   1.801 +  while (mCurStart != mEncodingHeader &&
   1.802 +         *mCurStart != ',' && !nsCRT::IsAsciiSpace(*mCurStart))
   1.803 +    --mCurStart;
   1.804 +  if (*mCurStart == ',' || nsCRT::IsAsciiSpace(*mCurStart))
   1.805 +    ++mCurStart; // we stopped because of a weird char, so move up one
   1.806 +
   1.807 +  // At this point mCurStart and mCurEnd bracket the encoding string
   1.808 +  // we want.  Check that it's not "identity"
   1.809 +  if (Substring(mCurStart, mCurEnd).Equals("identity",
   1.810 +                                           nsCaseInsensitiveCStringComparator())) {
   1.811 +    mCurEnd = mCurStart;
   1.812 +    return PrepareForNext();
   1.813 +  }
   1.814 +
   1.815 +  mReady = true;
   1.816 +  return NS_OK;
   1.817 +}
   1.818 +
   1.819 +
   1.820 +//-----------------------------------------------------------------------------
   1.821 +// HttpBaseChannel::nsIHttpChannel
   1.822 +//-----------------------------------------------------------------------------
   1.823 +
   1.824 +NS_IMETHODIMP
   1.825 +HttpBaseChannel::GetRequestMethod(nsACString& aMethod)
   1.826 +{
   1.827 +  aMethod = mRequestHead.Method();
   1.828 +  return NS_OK;
   1.829 +}
   1.830 +
   1.831 +NS_IMETHODIMP
   1.832 +HttpBaseChannel::SetRequestMethod(const nsACString& aMethod)
   1.833 +{
   1.834 +  ENSURE_CALLED_BEFORE_CONNECT();
   1.835 +
   1.836 +  const nsCString& flatMethod = PromiseFlatCString(aMethod);
   1.837 +
   1.838 +  // Method names are restricted to valid HTTP tokens.
   1.839 +  if (!nsHttp::IsValidToken(flatMethod))
   1.840 +    return NS_ERROR_INVALID_ARG;
   1.841 +
   1.842 +  mRequestHead.SetMethod(flatMethod);
   1.843 +  return NS_OK;
   1.844 +}
   1.845 +
   1.846 +NS_IMETHODIMP
   1.847 +HttpBaseChannel::GetReferrer(nsIURI **referrer)
   1.848 +{
   1.849 +  NS_ENSURE_ARG_POINTER(referrer);
   1.850 +  *referrer = mReferrer;
   1.851 +  NS_IF_ADDREF(*referrer);
   1.852 +  return NS_OK;
   1.853 +}
   1.854 +
   1.855 +NS_IMETHODIMP
   1.856 +HttpBaseChannel::SetReferrer(nsIURI *referrer)
   1.857 +{
   1.858 +  ENSURE_CALLED_BEFORE_CONNECT();
   1.859 +
   1.860 +  // clear existing referrer, if any
   1.861 +  mReferrer = nullptr;
   1.862 +  mRequestHead.ClearHeader(nsHttp::Referer);
   1.863 +
   1.864 +  if (!referrer)
   1.865 +      return NS_OK;
   1.866 +
   1.867 +  // 0: never send referer
   1.868 +  // 1: send referer for direct user action
   1.869 +  // 2: always send referer
   1.870 +  uint32_t userReferrerLevel = gHttpHandler->ReferrerLevel();
   1.871 +
   1.872 +  // false: use real referrer
   1.873 +  // true: spoof with URI of the current request
   1.874 +  bool userSpoofReferrerSource = gHttpHandler->SpoofReferrerSource();
   1.875 +
   1.876 +  // 0: full URI
   1.877 +  // 1: scheme+host+port+path
   1.878 +  // 2: scheme+host+port
   1.879 +  int userReferrerTrimmingPolicy = gHttpHandler->ReferrerTrimmingPolicy();
   1.880 +
   1.881 +  // 0: send referer no matter what
   1.882 +  // 1: send referer ONLY when base domains match
   1.883 +  // 2: send referer ONLY when hosts match
   1.884 +  int userReferrerXOriginPolicy = gHttpHandler->ReferrerXOriginPolicy();
   1.885 +
   1.886 +  // check referrer blocking pref
   1.887 +  uint32_t referrerLevel;
   1.888 +  if (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI)
   1.889 +    referrerLevel = 1; // user action
   1.890 +  else
   1.891 +    referrerLevel = 2; // inline content
   1.892 +  if (userReferrerLevel < referrerLevel)
   1.893 +    return NS_OK;
   1.894 +
   1.895 +  nsCOMPtr<nsIURI> referrerGrip;
   1.896 +  nsresult rv;
   1.897 +  bool match;
   1.898 +
   1.899 +  //
   1.900 +  // Strip off "wyciwyg://123/" from wyciwyg referrers.
   1.901 +  //
   1.902 +  // XXX this really belongs elsewhere since wyciwyg URLs aren't part of necko.
   1.903 +  //   perhaps some sort of generic nsINestedURI could be used.  then, if an URI
   1.904 +  //   fails the whitelist test, then we could check for an inner URI and try
   1.905 +  //   that instead.  though, that might be too automatic.
   1.906 +  //
   1.907 +  rv = referrer->SchemeIs("wyciwyg", &match);
   1.908 +  if (NS_FAILED(rv)) return rv;
   1.909 +  if (match) {
   1.910 +    nsAutoCString path;
   1.911 +    rv = referrer->GetPath(path);
   1.912 +    if (NS_FAILED(rv)) return rv;
   1.913 +
   1.914 +    uint32_t pathLength = path.Length();
   1.915 +    if (pathLength <= 2) return NS_ERROR_FAILURE;
   1.916 +
   1.917 +    // Path is of the form "//123/http://foo/bar", with a variable number of
   1.918 +    // digits. To figure out where the "real" URL starts, search path for a
   1.919 +    // '/', starting at the third character.
   1.920 +    int32_t slashIndex = path.FindChar('/', 2);
   1.921 +    if (slashIndex == kNotFound) return NS_ERROR_FAILURE;
   1.922 +
   1.923 +    // Get charset of the original URI so we can pass it to our fixed up URI.
   1.924 +    nsAutoCString charset;
   1.925 +    referrer->GetOriginCharset(charset);
   1.926 +
   1.927 +    // Replace |referrer| with a URI without wyciwyg://123/.
   1.928 +    rv = NS_NewURI(getter_AddRefs(referrerGrip),
   1.929 +                   Substring(path, slashIndex + 1, pathLength - slashIndex - 1),
   1.930 +                   charset.get());
   1.931 +    if (NS_FAILED(rv)) return rv;
   1.932 +
   1.933 +    referrer = referrerGrip.get();
   1.934 +  }
   1.935 +
   1.936 +  //
   1.937 +  // block referrer if not on our white list...
   1.938 +  //
   1.939 +  static const char *const referrerWhiteList[] = {
   1.940 +    "http",
   1.941 +    "https",
   1.942 +    "ftp",
   1.943 +    nullptr
   1.944 +  };
   1.945 +  match = false;
   1.946 +  const char *const *scheme = referrerWhiteList;
   1.947 +  for (; *scheme && !match; ++scheme) {
   1.948 +    rv = referrer->SchemeIs(*scheme, &match);
   1.949 +    if (NS_FAILED(rv)) return rv;
   1.950 +  }
   1.951 +  if (!match)
   1.952 +    return NS_OK; // kick out....
   1.953 +
   1.954 +  //
   1.955 +  // Handle secure referrals.
   1.956 +  //
   1.957 +  // Support referrals from a secure server if this is a secure site
   1.958 +  // and (optionally) if the host names are the same.
   1.959 +  //
   1.960 +  rv = referrer->SchemeIs("https", &match);
   1.961 +  if (NS_FAILED(rv)) return rv;
   1.962 +  if (match) {
   1.963 +    rv = mURI->SchemeIs("https", &match);
   1.964 +    if (NS_FAILED(rv)) return rv;
   1.965 +    if (!match)
   1.966 +      return NS_OK;
   1.967 +
   1.968 +    if (!gHttpHandler->SendSecureXSiteReferrer()) {
   1.969 +      nsAutoCString referrerHost;
   1.970 +      nsAutoCString host;
   1.971 +
   1.972 +      rv = referrer->GetAsciiHost(referrerHost);
   1.973 +      if (NS_FAILED(rv)) return rv;
   1.974 +
   1.975 +      rv = mURI->GetAsciiHost(host);
   1.976 +      if (NS_FAILED(rv)) return rv;
   1.977 +
   1.978 +      // GetAsciiHost returns lowercase hostname.
   1.979 +      if (!referrerHost.Equals(host))
   1.980 +        return NS_OK;
   1.981 +    }
   1.982 +  }
   1.983 +
   1.984 +  nsCOMPtr<nsIURI> clone;
   1.985 +  //
   1.986 +  // we need to clone the referrer, so we can:
   1.987 +  //  (1) modify it
   1.988 +  //  (2) keep a reference to it after returning from this function
   1.989 +  //
   1.990 +  // Use CloneIgnoringRef to strip away any fragment per RFC 2616 section 14.36
   1.991 +  rv = referrer->CloneIgnoringRef(getter_AddRefs(clone));
   1.992 +  if (NS_FAILED(rv)) return rv;
   1.993 +
   1.994 +  nsAutoCString currentHost;
   1.995 +  nsAutoCString referrerHost;
   1.996 +
   1.997 +  rv = mURI->GetAsciiHost(currentHost);
   1.998 +  if (NS_FAILED(rv)) return rv;
   1.999 +
  1.1000 +  rv = clone->GetAsciiHost(referrerHost);
  1.1001 +  if (NS_FAILED(rv)) return rv;
  1.1002 +
  1.1003 +  // check policy for sending ref only when hosts match
  1.1004 +  if (userReferrerXOriginPolicy == 2 && !currentHost.Equals(referrerHost))
  1.1005 +    return NS_OK;
  1.1006 +
  1.1007 +  if (userReferrerXOriginPolicy == 1) {
  1.1008 +    nsAutoCString currentDomain = currentHost;
  1.1009 +    nsAutoCString referrerDomain = referrerHost;
  1.1010 +    uint32_t extraDomains = 0;
  1.1011 +    nsCOMPtr<nsIEffectiveTLDService> eTLDService = do_GetService(
  1.1012 +      NS_EFFECTIVETLDSERVICE_CONTRACTID);
  1.1013 +    if (eTLDService) {
  1.1014 +      rv = eTLDService->GetBaseDomain(mURI, extraDomains, currentDomain);
  1.1015 +      if (NS_FAILED(rv)) return rv;
  1.1016 +      rv = eTLDService->GetBaseDomain(clone, extraDomains, referrerDomain); 
  1.1017 +      if (NS_FAILED(rv)) return rv;
  1.1018 +    }
  1.1019 +
  1.1020 +    // check policy for sending only when effective top level domain matches.
  1.1021 +    // this falls back on using host if eTLDService does not work
  1.1022 +    if (!currentDomain.Equals(referrerDomain))
  1.1023 +      return NS_OK;
  1.1024 +  }
  1.1025 +
  1.1026 +  // send spoofed referrer if desired
  1.1027 +  if (userSpoofReferrerSource) {
  1.1028 +    nsCOMPtr<nsIURI> mURIclone;
  1.1029 +    rv = mURI->CloneIgnoringRef(getter_AddRefs(mURIclone));
  1.1030 +    if (NS_FAILED(rv)) return rv;
  1.1031 +    clone = mURIclone;
  1.1032 +    currentHost = referrerHost;
  1.1033 +  }
  1.1034 +
  1.1035 +  // strip away any userpass; we don't want to be giving out passwords ;-)
  1.1036 +  rv = clone->SetUserPass(EmptyCString());
  1.1037 +  if (NS_FAILED(rv)) return rv;
  1.1038 +
  1.1039 +  nsAutoCString spec;
  1.1040 +
  1.1041 +  // check how much referer to send
  1.1042 +  switch (userReferrerTrimmingPolicy) {
  1.1043 +
  1.1044 +  case 1: {
  1.1045 +    // scheme+host+port+path
  1.1046 +    nsAutoCString prepath, path;
  1.1047 +    rv = clone->GetPrePath(prepath);
  1.1048 +    if (NS_FAILED(rv)) return rv;
  1.1049 +
  1.1050 +    nsCOMPtr<nsIURL> url(do_QueryInterface(clone));
  1.1051 +    if (!url) {
  1.1052 +      // if this isn't a url, play it safe
  1.1053 +      // and just send the prepath
  1.1054 +      spec = prepath;
  1.1055 +      break;
  1.1056 +    }
  1.1057 +    rv = url->GetFilePath(path);
  1.1058 +    if (NS_FAILED(rv)) return rv;
  1.1059 +    spec = prepath + path;
  1.1060 +    break;
  1.1061 +  }
  1.1062 +  case 2:
  1.1063 +    // scheme+host+port
  1.1064 +    rv = clone->GetPrePath(spec);
  1.1065 +    if (NS_FAILED(rv)) return rv;
  1.1066 +    break;
  1.1067 +
  1.1068 +  default:
  1.1069 +    // full URI
  1.1070 +    rv = clone->GetAsciiSpec(spec);
  1.1071 +    if (NS_FAILED(rv)) return rv;
  1.1072 +    break;
  1.1073 +  }
  1.1074 +
  1.1075 +  // finally, remember the referrer URI and set the Referer header.
  1.1076 +  mReferrer = clone;
  1.1077 +  mRequestHead.SetHeader(nsHttp::Referer, spec);
  1.1078 +  return NS_OK;
  1.1079 +}
  1.1080 +
  1.1081 +NS_IMETHODIMP
  1.1082 +HttpBaseChannel::GetProxyURI(nsIURI** proxyURI)
  1.1083 +{
  1.1084 +  NS_ENSURE_ARG_POINTER(proxyURI);
  1.1085 +  *proxyURI = mProxyURI;
  1.1086 +  NS_IF_ADDREF(*proxyURI);
  1.1087 +  return NS_OK;
  1.1088 +}
  1.1089 +
  1.1090 +NS_IMETHODIMP
  1.1091 +HttpBaseChannel::GetRequestHeader(const nsACString& aHeader,
  1.1092 +                                  nsACString& aValue)
  1.1093 +{
  1.1094 +  // XXX might be better to search the header list directly instead of
  1.1095 +  // hitting the http atom hash table.
  1.1096 +  nsHttpAtom atom = nsHttp::ResolveAtom(aHeader);
  1.1097 +  if (!atom)
  1.1098 +    return NS_ERROR_NOT_AVAILABLE;
  1.1099 +
  1.1100 +  return mRequestHead.GetHeader(atom, aValue);
  1.1101 +}
  1.1102 +
  1.1103 +NS_IMETHODIMP
  1.1104 +HttpBaseChannel::SetRequestHeader(const nsACString& aHeader,
  1.1105 +                                  const nsACString& aValue,
  1.1106 +                                  bool aMerge)
  1.1107 +{
  1.1108 +  const nsCString &flatHeader = PromiseFlatCString(aHeader);
  1.1109 +  const nsCString &flatValue  = PromiseFlatCString(aValue);
  1.1110 +
  1.1111 +  LOG(("HttpBaseChannel::SetRequestHeader [this=%p header=\"%s\" value=\"%s\" merge=%u]\n",
  1.1112 +      this, flatHeader.get(), flatValue.get(), aMerge));
  1.1113 +
  1.1114 +  // Header names are restricted to valid HTTP tokens.
  1.1115 +  if (!nsHttp::IsValidToken(flatHeader))
  1.1116 +    return NS_ERROR_INVALID_ARG;
  1.1117 +
  1.1118 +  // Header values MUST NOT contain line-breaks.  RFC 2616 technically
  1.1119 +  // permits CTL characters, including CR and LF, in header values provided
  1.1120 +  // they are quoted.  However, this can lead to problems if servers do not
  1.1121 +  // interpret quoted strings properly.  Disallowing CR and LF here seems
  1.1122 +  // reasonable and keeps things simple.  We also disallow a null byte.
  1.1123 +  if (flatValue.FindCharInSet("\r\n") != kNotFound ||
  1.1124 +      flatValue.Length() != strlen(flatValue.get()))
  1.1125 +    return NS_ERROR_INVALID_ARG;
  1.1126 +
  1.1127 +  nsHttpAtom atom = nsHttp::ResolveAtom(flatHeader.get());
  1.1128 +  if (!atom) {
  1.1129 +    NS_WARNING("failed to resolve atom");
  1.1130 +    return NS_ERROR_NOT_AVAILABLE;
  1.1131 +  }
  1.1132 +
  1.1133 +  return mRequestHead.SetHeader(atom, flatValue, aMerge);
  1.1134 +}
  1.1135 +
  1.1136 +NS_IMETHODIMP
  1.1137 +HttpBaseChannel::VisitRequestHeaders(nsIHttpHeaderVisitor *visitor)
  1.1138 +{
  1.1139 +  return mRequestHead.Headers().VisitHeaders(visitor);
  1.1140 +}
  1.1141 +
  1.1142 +NS_IMETHODIMP
  1.1143 +HttpBaseChannel::GetResponseHeader(const nsACString &header, nsACString &value)
  1.1144 +{
  1.1145 +  if (!mResponseHead)
  1.1146 +    return NS_ERROR_NOT_AVAILABLE;
  1.1147 +
  1.1148 +  nsHttpAtom atom = nsHttp::ResolveAtom(header);
  1.1149 +  if (!atom)
  1.1150 +    return NS_ERROR_NOT_AVAILABLE;
  1.1151 +
  1.1152 +  return mResponseHead->GetHeader(atom, value);
  1.1153 +}
  1.1154 +
  1.1155 +NS_IMETHODIMP
  1.1156 +HttpBaseChannel::SetResponseHeader(const nsACString& header,
  1.1157 +                                   const nsACString& value,
  1.1158 +                                   bool merge)
  1.1159 +{
  1.1160 +  LOG(("HttpBaseChannel::SetResponseHeader [this=%p header=\"%s\" value=\"%s\" merge=%u]\n",
  1.1161 +      this, PromiseFlatCString(header).get(), PromiseFlatCString(value).get(), merge));
  1.1162 +
  1.1163 +  if (!mResponseHead)
  1.1164 +    return NS_ERROR_NOT_AVAILABLE;
  1.1165 +
  1.1166 +  nsHttpAtom atom = nsHttp::ResolveAtom(header);
  1.1167 +  if (!atom)
  1.1168 +    return NS_ERROR_NOT_AVAILABLE;
  1.1169 +
  1.1170 +  // these response headers must not be changed
  1.1171 +  if (atom == nsHttp::Content_Type ||
  1.1172 +      atom == nsHttp::Content_Length ||
  1.1173 +      atom == nsHttp::Content_Encoding ||
  1.1174 +      atom == nsHttp::Trailer ||
  1.1175 +      atom == nsHttp::Transfer_Encoding)
  1.1176 +    return NS_ERROR_ILLEGAL_VALUE;
  1.1177 +
  1.1178 +  mResponseHeadersModified = true;
  1.1179 +
  1.1180 +  return mResponseHead->SetHeader(atom, value, merge);
  1.1181 +}
  1.1182 +
  1.1183 +NS_IMETHODIMP
  1.1184 +HttpBaseChannel::VisitResponseHeaders(nsIHttpHeaderVisitor *visitor)
  1.1185 +{
  1.1186 +  if (!mResponseHead)
  1.1187 +    return NS_ERROR_NOT_AVAILABLE;
  1.1188 +  return mResponseHead->Headers().VisitHeaders(visitor);
  1.1189 +}
  1.1190 +
  1.1191 +NS_IMETHODIMP
  1.1192 +HttpBaseChannel::GetAllowPipelining(bool *value)
  1.1193 +{
  1.1194 +  NS_ENSURE_ARG_POINTER(value);
  1.1195 +  *value = mAllowPipelining;
  1.1196 +  return NS_OK;
  1.1197 +}
  1.1198 +
  1.1199 +NS_IMETHODIMP
  1.1200 +HttpBaseChannel::SetAllowPipelining(bool value)
  1.1201 +{
  1.1202 +  ENSURE_CALLED_BEFORE_CONNECT();
  1.1203 +
  1.1204 +  mAllowPipelining = value;
  1.1205 +  return NS_OK;
  1.1206 +}
  1.1207 +
  1.1208 +NS_IMETHODIMP
  1.1209 +HttpBaseChannel::GetRedirectionLimit(uint32_t *value)
  1.1210 +{
  1.1211 +  NS_ENSURE_ARG_POINTER(value);
  1.1212 +  *value = mRedirectionLimit;
  1.1213 +  return NS_OK;
  1.1214 +}
  1.1215 +
  1.1216 +NS_IMETHODIMP
  1.1217 +HttpBaseChannel::SetRedirectionLimit(uint32_t value)
  1.1218 +{
  1.1219 +  ENSURE_CALLED_BEFORE_CONNECT();
  1.1220 +
  1.1221 +  mRedirectionLimit = std::min<uint32_t>(value, 0xff);
  1.1222 +  return NS_OK;
  1.1223 +}
  1.1224 +
  1.1225 +NS_IMETHODIMP
  1.1226 +HttpBaseChannel::IsNoStoreResponse(bool *value)
  1.1227 +{
  1.1228 +  if (!mResponseHead)
  1.1229 +    return NS_ERROR_NOT_AVAILABLE;
  1.1230 +  *value = mResponseHead->NoStore();
  1.1231 +  return NS_OK;
  1.1232 +}
  1.1233 +
  1.1234 +NS_IMETHODIMP
  1.1235 +HttpBaseChannel::IsNoCacheResponse(bool *value)
  1.1236 +{
  1.1237 +  if (!mResponseHead)
  1.1238 +    return NS_ERROR_NOT_AVAILABLE;
  1.1239 +  *value = mResponseHead->NoCache();
  1.1240 +  if (!*value)
  1.1241 +    *value = mResponseHead->ExpiresInPast();
  1.1242 +  return NS_OK;
  1.1243 +}
  1.1244 +
  1.1245 +NS_IMETHODIMP
  1.1246 +HttpBaseChannel::GetResponseStatus(uint32_t *aValue)
  1.1247 +{
  1.1248 +  if (!mResponseHead)
  1.1249 +    return NS_ERROR_NOT_AVAILABLE;
  1.1250 +  *aValue = mResponseHead->Status();
  1.1251 +  return NS_OK;
  1.1252 +}
  1.1253 +
  1.1254 +NS_IMETHODIMP
  1.1255 +HttpBaseChannel::GetResponseStatusText(nsACString& aValue)
  1.1256 +{
  1.1257 +  if (!mResponseHead)
  1.1258 +    return NS_ERROR_NOT_AVAILABLE;
  1.1259 +  aValue = mResponseHead->StatusText();
  1.1260 +  return NS_OK;
  1.1261 +}
  1.1262 +
  1.1263 +NS_IMETHODIMP
  1.1264 +HttpBaseChannel::GetRequestSucceeded(bool *aValue)
  1.1265 +{
  1.1266 +  if (!mResponseHead)
  1.1267 +    return NS_ERROR_NOT_AVAILABLE;
  1.1268 +  uint32_t status = mResponseHead->Status();
  1.1269 +  *aValue = (status / 100 == 2);
  1.1270 +  return NS_OK;
  1.1271 +}
  1.1272 +
  1.1273 +NS_IMETHODIMP
  1.1274 +HttpBaseChannel::RedirectTo(nsIURI *newURI)
  1.1275 +{
  1.1276 +  // We can only redirect unopened channels
  1.1277 +  ENSURE_CALLED_BEFORE_CONNECT();
  1.1278 +
  1.1279 +  // The redirect is stored internally for use in AsyncOpen
  1.1280 +  mAPIRedirectToURI = newURI;
  1.1281 +
  1.1282 +  return NS_OK;
  1.1283 +}
  1.1284 +
  1.1285 +//-----------------------------------------------------------------------------
  1.1286 +// HttpBaseChannel::nsIHttpChannelInternal
  1.1287 +//-----------------------------------------------------------------------------
  1.1288 +
  1.1289 +NS_IMETHODIMP
  1.1290 +HttpBaseChannel::GetDocumentURI(nsIURI **aDocumentURI)
  1.1291 +{
  1.1292 +  NS_ENSURE_ARG_POINTER(aDocumentURI);
  1.1293 +  *aDocumentURI = mDocumentURI;
  1.1294 +  NS_IF_ADDREF(*aDocumentURI);
  1.1295 +  return NS_OK;
  1.1296 +}
  1.1297 +
  1.1298 +NS_IMETHODIMP
  1.1299 +HttpBaseChannel::SetDocumentURI(nsIURI *aDocumentURI)
  1.1300 +{
  1.1301 +  ENSURE_CALLED_BEFORE_CONNECT();
  1.1302 +
  1.1303 +  mDocumentURI = aDocumentURI;
  1.1304 +  return NS_OK;
  1.1305 +}
  1.1306 +
  1.1307 +NS_IMETHODIMP
  1.1308 +HttpBaseChannel::GetRequestVersion(uint32_t *major, uint32_t *minor)
  1.1309 +{
  1.1310 +  nsHttpVersion version = mRequestHead.Version();
  1.1311 +
  1.1312 +  if (major) { *major = version / 10; }
  1.1313 +  if (minor) { *minor = version % 10; }
  1.1314 +
  1.1315 +  return NS_OK;
  1.1316 +}
  1.1317 +
  1.1318 +NS_IMETHODIMP
  1.1319 +HttpBaseChannel::GetResponseVersion(uint32_t *major, uint32_t *minor)
  1.1320 +{
  1.1321 +  if (!mResponseHead)
  1.1322 +  {
  1.1323 +    *major = *minor = 0; // we should at least be kind about it
  1.1324 +    return NS_ERROR_NOT_AVAILABLE;
  1.1325 +  }
  1.1326 +
  1.1327 +  nsHttpVersion version = mResponseHead->Version();
  1.1328 +
  1.1329 +  if (major) { *major = version / 10; }
  1.1330 +  if (minor) { *minor = version % 10; }
  1.1331 +
  1.1332 +  return NS_OK;
  1.1333 +}
  1.1334 +
  1.1335 +namespace {
  1.1336 +
  1.1337 +class CookieNotifierRunnable : public nsRunnable
  1.1338 +{
  1.1339 +public:
  1.1340 +  CookieNotifierRunnable(HttpBaseChannel* aChannel, char const * aCookie)
  1.1341 +    : mChannel(aChannel), mCookie(aCookie)
  1.1342 +  { }
  1.1343 +
  1.1344 +  NS_IMETHOD Run()
  1.1345 +  {
  1.1346 +    nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
  1.1347 +    if (obs) {
  1.1348 +      obs->NotifyObservers(static_cast<nsIChannel*>(mChannel.get()),
  1.1349 +                           "http-on-response-set-cookie",
  1.1350 +                           mCookie.get());
  1.1351 +    }
  1.1352 +    return NS_OK;
  1.1353 +  }
  1.1354 +
  1.1355 +private:
  1.1356 +  nsRefPtr<HttpBaseChannel> mChannel;
  1.1357 +  NS_ConvertASCIItoUTF16 mCookie;
  1.1358 +};
  1.1359 +
  1.1360 +} // anonymous namespace
  1.1361 +
  1.1362 +NS_IMETHODIMP
  1.1363 +HttpBaseChannel::SetCookie(const char *aCookieHeader)
  1.1364 +{
  1.1365 +  if (mLoadFlags & LOAD_ANONYMOUS)
  1.1366 +    return NS_OK;
  1.1367 +
  1.1368 +  // empty header isn't an error
  1.1369 +  if (!(aCookieHeader && *aCookieHeader))
  1.1370 +    return NS_OK;
  1.1371 +
  1.1372 +  nsICookieService *cs = gHttpHandler->GetCookieService();
  1.1373 +  NS_ENSURE_TRUE(cs, NS_ERROR_FAILURE);
  1.1374 +
  1.1375 +  nsresult rv =
  1.1376 +    cs->SetCookieStringFromHttp(mURI, nullptr, nullptr, aCookieHeader,
  1.1377 +                                mResponseHead->PeekHeader(nsHttp::Date), this);
  1.1378 +  if (NS_SUCCEEDED(rv)) {
  1.1379 +    nsRefPtr<CookieNotifierRunnable> r =
  1.1380 +      new CookieNotifierRunnable(this, aCookieHeader);
  1.1381 +    NS_DispatchToMainThread(r);
  1.1382 +  }
  1.1383 +  return rv;
  1.1384 +}
  1.1385 +
  1.1386 +NS_IMETHODIMP
  1.1387 +HttpBaseChannel::GetForceAllowThirdPartyCookie(bool *aForce)
  1.1388 +{
  1.1389 +  *aForce = mForceAllowThirdPartyCookie;
  1.1390 +  return NS_OK;
  1.1391 +}
  1.1392 +
  1.1393 +NS_IMETHODIMP
  1.1394 +HttpBaseChannel::SetForceAllowThirdPartyCookie(bool aForce)
  1.1395 +{
  1.1396 +  ENSURE_CALLED_BEFORE_ASYNC_OPEN();
  1.1397 +
  1.1398 +  mForceAllowThirdPartyCookie = aForce;
  1.1399 +  return NS_OK;
  1.1400 +}
  1.1401 +
  1.1402 +NS_IMETHODIMP
  1.1403 +HttpBaseChannel::GetCanceled(bool *aCanceled)
  1.1404 +{
  1.1405 +  *aCanceled = mCanceled;
  1.1406 +  return NS_OK;
  1.1407 +}
  1.1408 +
  1.1409 +NS_IMETHODIMP
  1.1410 +HttpBaseChannel::GetChannelIsForDownload(bool *aChannelIsForDownload)
  1.1411 +{
  1.1412 +  *aChannelIsForDownload = mChannelIsForDownload;
  1.1413 +  return NS_OK;
  1.1414 +}
  1.1415 +
  1.1416 +NS_IMETHODIMP
  1.1417 +HttpBaseChannel::SetChannelIsForDownload(bool aChannelIsForDownload)
  1.1418 +{
  1.1419 +  mChannelIsForDownload = aChannelIsForDownload;
  1.1420 +  return NS_OK;
  1.1421 +}
  1.1422 +
  1.1423 +NS_IMETHODIMP
  1.1424 +HttpBaseChannel::SetCacheKeysRedirectChain(nsTArray<nsCString> *cacheKeys)
  1.1425 +{
  1.1426 +  mRedirectedCachekeys = cacheKeys;
  1.1427 +  return NS_OK;
  1.1428 +}
  1.1429 +
  1.1430 +NS_IMETHODIMP
  1.1431 +HttpBaseChannel::GetLocalAddress(nsACString& addr)
  1.1432 +{
  1.1433 +  if (mSelfAddr.raw.family == PR_AF_UNSPEC)
  1.1434 +    return NS_ERROR_NOT_AVAILABLE;
  1.1435 +
  1.1436 +  addr.SetCapacity(kIPv6CStrBufSize);
  1.1437 +  NetAddrToString(&mSelfAddr, addr.BeginWriting(), kIPv6CStrBufSize);
  1.1438 +  addr.SetLength(strlen(addr.BeginReading()));
  1.1439 +
  1.1440 +  return NS_OK;
  1.1441 +}
  1.1442 +
  1.1443 +NS_IMETHODIMP
  1.1444 +HttpBaseChannel::TakeAllSecurityMessages(
  1.1445 +    nsCOMArray<nsISecurityConsoleMessage> &aMessages)
  1.1446 +{
  1.1447 +  aMessages.Clear();
  1.1448 +  aMessages.SwapElements(mSecurityConsoleMessages);
  1.1449 +  return NS_OK;
  1.1450 +}
  1.1451 +
  1.1452 +/* Please use this method with care. This can cause the message
  1.1453 + * queue to grow large and cause the channel to take up a lot
  1.1454 + * of memory. Use only static string messages and do not add
  1.1455 + * server side data to the queue, as that can be large.
  1.1456 + * Add only a limited number of messages to the queue to keep
  1.1457 + * the channel size down and do so only in rare erroneous situations.
  1.1458 + * More information can be found here:
  1.1459 + * https://bugzilla.mozilla.org/show_bug.cgi?id=846918
  1.1460 + */
  1.1461 +NS_IMETHODIMP
  1.1462 +HttpBaseChannel::AddSecurityMessage(const nsAString &aMessageTag,
  1.1463 +    const nsAString &aMessageCategory)
  1.1464 +{
  1.1465 +  nsresult rv;
  1.1466 +  nsCOMPtr<nsISecurityConsoleMessage> message =
  1.1467 +    do_CreateInstance(NS_SECURITY_CONSOLE_MESSAGE_CONTRACTID, &rv);
  1.1468 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1469 +  message->SetTag(aMessageTag);
  1.1470 +  message->SetCategory(aMessageCategory);
  1.1471 +  mSecurityConsoleMessages.AppendElement(message);
  1.1472 +  return NS_OK;
  1.1473 +}
  1.1474 +
  1.1475 +NS_IMETHODIMP
  1.1476 +HttpBaseChannel::GetLocalPort(int32_t* port)
  1.1477 +{
  1.1478 +  NS_ENSURE_ARG_POINTER(port);
  1.1479 +
  1.1480 +  if (mSelfAddr.raw.family == PR_AF_INET) {
  1.1481 +    *port = (int32_t)ntohs(mSelfAddr.inet.port);
  1.1482 +  }
  1.1483 +  else if (mSelfAddr.raw.family == PR_AF_INET6) {
  1.1484 +    *port = (int32_t)ntohs(mSelfAddr.inet6.port);
  1.1485 +  }
  1.1486 +  else
  1.1487 +    return NS_ERROR_NOT_AVAILABLE;
  1.1488 +
  1.1489 +  return NS_OK;
  1.1490 +}
  1.1491 +
  1.1492 +NS_IMETHODIMP
  1.1493 +HttpBaseChannel::GetRemoteAddress(nsACString& addr)
  1.1494 +{
  1.1495 +  if (mPeerAddr.raw.family == PR_AF_UNSPEC)
  1.1496 +    return NS_ERROR_NOT_AVAILABLE;
  1.1497 +
  1.1498 +  addr.SetCapacity(kIPv6CStrBufSize);
  1.1499 +  NetAddrToString(&mPeerAddr, addr.BeginWriting(), kIPv6CStrBufSize);
  1.1500 +  addr.SetLength(strlen(addr.BeginReading()));
  1.1501 +
  1.1502 +  return NS_OK;
  1.1503 +}
  1.1504 +
  1.1505 +NS_IMETHODIMP
  1.1506 +HttpBaseChannel::GetRemotePort(int32_t* port)
  1.1507 +{
  1.1508 +  NS_ENSURE_ARG_POINTER(port);
  1.1509 +
  1.1510 +  if (mPeerAddr.raw.family == PR_AF_INET) {
  1.1511 +    *port = (int32_t)ntohs(mPeerAddr.inet.port);
  1.1512 +  }
  1.1513 +  else if (mPeerAddr.raw.family == PR_AF_INET6) {
  1.1514 +    *port = (int32_t)ntohs(mPeerAddr.inet6.port);
  1.1515 +  }
  1.1516 +  else
  1.1517 +    return NS_ERROR_NOT_AVAILABLE;
  1.1518 +
  1.1519 +  return NS_OK;
  1.1520 +}
  1.1521 +
  1.1522 +NS_IMETHODIMP
  1.1523 +HttpBaseChannel::HTTPUpgrade(const nsACString &aProtocolName,
  1.1524 +                             nsIHttpUpgradeListener *aListener)
  1.1525 +{
  1.1526 +    NS_ENSURE_ARG(!aProtocolName.IsEmpty());
  1.1527 +    NS_ENSURE_ARG_POINTER(aListener);
  1.1528 +
  1.1529 +    mUpgradeProtocol = aProtocolName;
  1.1530 +    mUpgradeProtocolCallback = aListener;
  1.1531 +    return NS_OK;
  1.1532 +}
  1.1533 +
  1.1534 +NS_IMETHODIMP
  1.1535 +HttpBaseChannel::GetAllowSpdy(bool *aAllowSpdy)
  1.1536 +{
  1.1537 +  NS_ENSURE_ARG_POINTER(aAllowSpdy);
  1.1538 +
  1.1539 +  *aAllowSpdy = mAllowSpdy;
  1.1540 +  return NS_OK;
  1.1541 +}
  1.1542 +
  1.1543 +NS_IMETHODIMP
  1.1544 +HttpBaseChannel::SetAllowSpdy(bool aAllowSpdy)
  1.1545 +{
  1.1546 +  mAllowSpdy = aAllowSpdy;
  1.1547 +  return NS_OK;
  1.1548 +}
  1.1549 +
  1.1550 +NS_IMETHODIMP
  1.1551 +HttpBaseChannel::GetLoadAsBlocking(bool *aLoadAsBlocking)
  1.1552 +{
  1.1553 +  NS_ENSURE_ARG_POINTER(aLoadAsBlocking);
  1.1554 +  *aLoadAsBlocking = mLoadAsBlocking;
  1.1555 +  return NS_OK;
  1.1556 +}
  1.1557 +
  1.1558 +NS_IMETHODIMP
  1.1559 +HttpBaseChannel::SetLoadAsBlocking(bool aLoadAsBlocking)
  1.1560 +{
  1.1561 +  mLoadAsBlocking = aLoadAsBlocking;
  1.1562 +  return NS_OK;
  1.1563 +}
  1.1564 +
  1.1565 +NS_IMETHODIMP
  1.1566 +HttpBaseChannel::GetLoadUnblocked(bool *aLoadUnblocked)
  1.1567 +{
  1.1568 +  NS_ENSURE_ARG_POINTER(aLoadUnblocked);
  1.1569 +  *aLoadUnblocked = mLoadUnblocked;
  1.1570 +  return NS_OK;
  1.1571 +}
  1.1572 +
  1.1573 +NS_IMETHODIMP
  1.1574 +HttpBaseChannel::SetLoadUnblocked(bool aLoadUnblocked)
  1.1575 +{
  1.1576 +  mLoadUnblocked = aLoadUnblocked;
  1.1577 +  return NS_OK;
  1.1578 +}
  1.1579 +
  1.1580 +NS_IMETHODIMP
  1.1581 +HttpBaseChannel::GetApiRedirectToURI(nsIURI ** aResult)
  1.1582 +{
  1.1583 +  NS_ENSURE_ARG_POINTER(aResult);
  1.1584 +  NS_IF_ADDREF(*aResult = mAPIRedirectToURI);
  1.1585 +  return NS_OK;
  1.1586 +}
  1.1587 +
  1.1588 +NS_IMETHODIMP
  1.1589 +HttpBaseChannel::GetResponseTimeoutEnabled(bool *aEnable)
  1.1590 +{
  1.1591 +  if (NS_WARN_IF(!aEnable)) {
  1.1592 +    return NS_ERROR_NULL_POINTER;
  1.1593 +  }
  1.1594 +  *aEnable = mResponseTimeoutEnabled;
  1.1595 +  return NS_OK;
  1.1596 +}
  1.1597 +
  1.1598 +NS_IMETHODIMP
  1.1599 +HttpBaseChannel::SetResponseTimeoutEnabled(bool aEnable)
  1.1600 +{
  1.1601 +  mResponseTimeoutEnabled = aEnable;
  1.1602 +  return NS_OK;
  1.1603 +}
  1.1604 +
  1.1605 +//-----------------------------------------------------------------------------
  1.1606 +// HttpBaseChannel::nsISupportsPriority
  1.1607 +//-----------------------------------------------------------------------------
  1.1608 +
  1.1609 +NS_IMETHODIMP
  1.1610 +HttpBaseChannel::GetPriority(int32_t *value)
  1.1611 +{
  1.1612 +  *value = mPriority;
  1.1613 +  return NS_OK;
  1.1614 +}
  1.1615 +
  1.1616 +NS_IMETHODIMP
  1.1617 +HttpBaseChannel::AdjustPriority(int32_t delta)
  1.1618 +{
  1.1619 +  return SetPriority(mPriority + delta);
  1.1620 +}
  1.1621 +
  1.1622 +//-----------------------------------------------------------------------------
  1.1623 +// HttpBaseChannel::nsIResumableChannel
  1.1624 +//-----------------------------------------------------------------------------
  1.1625 +
  1.1626 +NS_IMETHODIMP
  1.1627 +HttpBaseChannel::GetEntityID(nsACString& aEntityID)
  1.1628 +{
  1.1629 +  // Don't return an entity ID for Non-GET requests which require
  1.1630 +  // additional data
  1.1631 +  if (!mRequestHead.IsGet()) {
  1.1632 +    return NS_ERROR_NOT_RESUMABLE;
  1.1633 +  }
  1.1634 +
  1.1635 +  uint64_t size = UINT64_MAX;
  1.1636 +  nsAutoCString etag, lastmod;
  1.1637 +  if (mResponseHead) {
  1.1638 +    // Don't return an entity if the server sent the following header:
  1.1639 +    // Accept-Ranges: none
  1.1640 +    // Not sending the Accept-Ranges header means we can still try
  1.1641 +    // sending range requests.
  1.1642 +    const char* acceptRanges =
  1.1643 +        mResponseHead->PeekHeader(nsHttp::Accept_Ranges);
  1.1644 +    if (acceptRanges &&
  1.1645 +        !nsHttp::FindToken(acceptRanges, "bytes", HTTP_HEADER_VALUE_SEPS)) {
  1.1646 +      return NS_ERROR_NOT_RESUMABLE;
  1.1647 +    }
  1.1648 +
  1.1649 +    size = mResponseHead->TotalEntitySize();
  1.1650 +    const char* cLastMod = mResponseHead->PeekHeader(nsHttp::Last_Modified);
  1.1651 +    if (cLastMod)
  1.1652 +      lastmod = cLastMod;
  1.1653 +    const char* cEtag = mResponseHead->PeekHeader(nsHttp::ETag);
  1.1654 +    if (cEtag)
  1.1655 +      etag = cEtag;
  1.1656 +  }
  1.1657 +  nsCString entityID;
  1.1658 +  NS_EscapeURL(etag.BeginReading(), etag.Length(), esc_AlwaysCopy |
  1.1659 +               esc_FileBaseName | esc_Forced, entityID);
  1.1660 +  entityID.Append('/');
  1.1661 +  entityID.AppendInt(int64_t(size));
  1.1662 +  entityID.Append('/');
  1.1663 +  entityID.Append(lastmod);
  1.1664 +  // NOTE: Appending lastmod as the last part avoids having to escape it
  1.1665 +
  1.1666 +  aEntityID = entityID;
  1.1667 +
  1.1668 +  return NS_OK;
  1.1669 +}
  1.1670 +
  1.1671 +//-----------------------------------------------------------------------------
  1.1672 +// nsHttpChannel::nsITraceableChannel
  1.1673 +//-----------------------------------------------------------------------------
  1.1674 +
  1.1675 +NS_IMETHODIMP
  1.1676 +HttpBaseChannel::SetNewListener(nsIStreamListener *aListener, nsIStreamListener **_retval)
  1.1677 +{
  1.1678 +  if (!mTracingEnabled)
  1.1679 +    return NS_ERROR_FAILURE;
  1.1680 +
  1.1681 +  NS_ENSURE_ARG_POINTER(aListener);
  1.1682 +
  1.1683 +  nsCOMPtr<nsIStreamListener> wrapper = new nsStreamListenerWrapper(mListener);
  1.1684 +
  1.1685 +  wrapper.forget(_retval);
  1.1686 +  mListener = aListener;
  1.1687 +  return NS_OK;
  1.1688 +}
  1.1689 +
  1.1690 +//-----------------------------------------------------------------------------
  1.1691 +// HttpBaseChannel helpers
  1.1692 +//-----------------------------------------------------------------------------
  1.1693 +
  1.1694 +void
  1.1695 +HttpBaseChannel::ReleaseListeners()
  1.1696 +{
  1.1697 +  MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread.");
  1.1698 +  
  1.1699 +  mListener = nullptr;
  1.1700 +  mListenerContext = nullptr;
  1.1701 +  mCallbacks = nullptr;
  1.1702 +  mProgressSink = nullptr;
  1.1703 +}
  1.1704 +
  1.1705 +void
  1.1706 +HttpBaseChannel::DoNotifyListener()
  1.1707 +{
  1.1708 +  // Make sure mIsPending is set to false. At this moment we are done from
  1.1709 +  // the point of view of our consumer and we have to report our self
  1.1710 +  // as not-pending.
  1.1711 +  if (mListener) {
  1.1712 +    mListener->OnStartRequest(this, mListenerContext);
  1.1713 +    mIsPending = false;
  1.1714 +    mListener->OnStopRequest(this, mListenerContext, mStatus);
  1.1715 +  } else {
  1.1716 +    mIsPending = false;
  1.1717 +  }
  1.1718 +  // We have to make sure to drop the references to listeners and callbacks
  1.1719 +  // no longer  needed
  1.1720 +  ReleaseListeners();
  1.1721 +
  1.1722 +  DoNotifyListenerCleanup();
  1.1723 +}
  1.1724 +
  1.1725 +void
  1.1726 +HttpBaseChannel::AddCookiesToRequest()
  1.1727 +{
  1.1728 +  if (mLoadFlags & LOAD_ANONYMOUS) {
  1.1729 +    return;
  1.1730 +  }
  1.1731 +
  1.1732 +  bool useCookieService =
  1.1733 +    (XRE_GetProcessType() == GeckoProcessType_Default);
  1.1734 +  nsXPIDLCString cookie;
  1.1735 +  if (useCookieService) {
  1.1736 +    nsICookieService *cs = gHttpHandler->GetCookieService();
  1.1737 +    if (cs) {
  1.1738 +      cs->GetCookieStringFromHttp(mURI,
  1.1739 +                                  nullptr,
  1.1740 +                                  this, getter_Copies(cookie));
  1.1741 +    }
  1.1742 +
  1.1743 +    if (cookie.IsEmpty()) {
  1.1744 +      cookie = mUserSetCookieHeader;
  1.1745 +    }
  1.1746 +    else if (!mUserSetCookieHeader.IsEmpty()) {
  1.1747 +      cookie.Append(NS_LITERAL_CSTRING("; ") + mUserSetCookieHeader);
  1.1748 +    }
  1.1749 +  }
  1.1750 +  else {
  1.1751 +    cookie = mUserSetCookieHeader;
  1.1752 +  }
  1.1753 +
  1.1754 +  // If we are in the child process, we want the parent seeing any
  1.1755 +  // cookie headers that might have been set by SetRequestHeader()
  1.1756 +  SetRequestHeader(nsDependentCString(nsHttp::Cookie), cookie, false);
  1.1757 +}
  1.1758 +
  1.1759 +static PLDHashOperator
  1.1760 +CopyProperties(const nsAString& aKey, nsIVariant *aData, void *aClosure)
  1.1761 +{
  1.1762 +  nsIWritablePropertyBag* bag = static_cast<nsIWritablePropertyBag*>
  1.1763 +                                           (aClosure);
  1.1764 +  bag->SetProperty(aKey, aData);
  1.1765 +  return PL_DHASH_NEXT;
  1.1766 +}
  1.1767 +
  1.1768 +bool
  1.1769 +HttpBaseChannel::ShouldRewriteRedirectToGET(uint32_t httpStatus,
  1.1770 +                                            nsHttpRequestHead::ParsedMethodType method)
  1.1771 +{
  1.1772 +  // for 301 and 302, only rewrite POST
  1.1773 +  if (httpStatus == 301 || httpStatus == 302)
  1.1774 +    return method == nsHttpRequestHead::kMethod_Post;
  1.1775 +
  1.1776 +  // rewrite for 303 unless it was HEAD
  1.1777 +  if (httpStatus == 303)
  1.1778 +    return method != nsHttpRequestHead::kMethod_Head;
  1.1779 +
  1.1780 +  // otherwise, such as for 307, do not rewrite
  1.1781 +  return false;
  1.1782 +}
  1.1783 +
  1.1784 +nsresult
  1.1785 +HttpBaseChannel::SetupReplacementChannel(nsIURI       *newURI,
  1.1786 +                                         nsIChannel   *newChannel,
  1.1787 +                                         bool          preserveMethod)
  1.1788 +{
  1.1789 +  LOG(("HttpBaseChannel::SetupReplacementChannel "
  1.1790 +     "[this=%p newChannel=%p preserveMethod=%d]",
  1.1791 +     this, newChannel, preserveMethod));
  1.1792 +  uint32_t newLoadFlags = mLoadFlags | LOAD_REPLACE;
  1.1793 +  // if the original channel was using SSL and this channel is not using
  1.1794 +  // SSL, then no need to inhibit persistent caching.  however, if the
  1.1795 +  // original channel was not using SSL and has INHIBIT_PERSISTENT_CACHING
  1.1796 +  // set, then allow the flag to apply to the redirected channel as well.
  1.1797 +  // since we force set INHIBIT_PERSISTENT_CACHING on all HTTPS channels,
  1.1798 +  // we only need to check if the original channel was using SSL.
  1.1799 +  bool usingSSL = false;
  1.1800 +  nsresult rv = mURI->SchemeIs("https", &usingSSL);
  1.1801 +  if (NS_SUCCEEDED(rv) && usingSSL)
  1.1802 +    newLoadFlags &= ~INHIBIT_PERSISTENT_CACHING;
  1.1803 +
  1.1804 +  // Do not pass along LOAD_CHECK_OFFLINE_CACHE
  1.1805 +  newLoadFlags &= ~nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE;
  1.1806 +
  1.1807 +  newChannel->SetLoadGroup(mLoadGroup);
  1.1808 +  newChannel->SetNotificationCallbacks(mCallbacks);
  1.1809 +  newChannel->SetLoadFlags(newLoadFlags);
  1.1810 +
  1.1811 +  // If our owner is a null principal it will have been set as a security
  1.1812 +  // measure, so we want to propagate it to the new channel.
  1.1813 +  nsCOMPtr<nsIPrincipal> ownerPrincipal = do_QueryInterface(mOwner);
  1.1814 +  if (ownerPrincipal && ownerPrincipal->GetIsNullPrincipal()) {
  1.1815 +    newChannel->SetOwner(mOwner);
  1.1816 +  }
  1.1817 +
  1.1818 +  // Try to preserve the privacy bit if it has been overridden
  1.1819 +  if (mPrivateBrowsingOverriden) {
  1.1820 +    nsCOMPtr<nsIPrivateBrowsingChannel> newPBChannel =
  1.1821 +      do_QueryInterface(newChannel);
  1.1822 +    if (newPBChannel) {
  1.1823 +      newPBChannel->SetPrivate(mPrivateBrowsing);
  1.1824 +    }
  1.1825 +  }
  1.1826 +
  1.1827 +  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel);
  1.1828 +  if (!httpChannel)
  1.1829 +    return NS_OK; // no other options to set
  1.1830 +
  1.1831 +  if (preserveMethod) {
  1.1832 +    nsCOMPtr<nsIUploadChannel> uploadChannel =
  1.1833 +      do_QueryInterface(httpChannel);
  1.1834 +    nsCOMPtr<nsIUploadChannel2> uploadChannel2 =
  1.1835 +      do_QueryInterface(httpChannel);
  1.1836 +    if (mUploadStream && (uploadChannel2 || uploadChannel)) {
  1.1837 +      // rewind upload stream
  1.1838 +      nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mUploadStream);
  1.1839 +      if (seekable)
  1.1840 +        seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
  1.1841 +
  1.1842 +      // replicate original call to SetUploadStream...
  1.1843 +      if (uploadChannel2) {
  1.1844 +        const char *ctype = mRequestHead.PeekHeader(nsHttp::Content_Type);
  1.1845 +        if (!ctype)
  1.1846 +          ctype = "";
  1.1847 +        const char *clen  = mRequestHead.PeekHeader(nsHttp::Content_Length);
  1.1848 +        int64_t len = clen ? nsCRT::atoll(clen) : -1;
  1.1849 +        uploadChannel2->ExplicitSetUploadStream(
  1.1850 +                                  mUploadStream, nsDependentCString(ctype), len,
  1.1851 +                                  mRequestHead.Method(),
  1.1852 +                                  mUploadStreamHasHeaders);
  1.1853 +      } else {
  1.1854 +        if (mUploadStreamHasHeaders) {
  1.1855 +          uploadChannel->SetUploadStream(mUploadStream, EmptyCString(),
  1.1856 +                           -1);
  1.1857 +        } else {
  1.1858 +          const char *ctype =
  1.1859 +            mRequestHead.PeekHeader(nsHttp::Content_Type);
  1.1860 +          const char *clen =
  1.1861 +            mRequestHead.PeekHeader(nsHttp::Content_Length);
  1.1862 +          if (!ctype) {
  1.1863 +            ctype = "application/octet-stream";
  1.1864 +          }
  1.1865 +          if (clen) {
  1.1866 +            uploadChannel->SetUploadStream(mUploadStream,
  1.1867 +                                           nsDependentCString(ctype),
  1.1868 +                                           nsCRT::atoll(clen));
  1.1869 +          }
  1.1870 +        }
  1.1871 +      }
  1.1872 +    }
  1.1873 +    // since preserveMethod is true, we need to ensure that the appropriate
  1.1874 +    // request method gets set on the channel, regardless of whether or not
  1.1875 +    // we set the upload stream above. This means SetRequestMethod() will
  1.1876 +    // be called twice if ExplicitSetUploadStream() gets called above.
  1.1877 +
  1.1878 +    httpChannel->SetRequestMethod(mRequestHead.Method());
  1.1879 +  }
  1.1880 +  // convey the referrer if one was used for this channel to the next one
  1.1881 +  if (mReferrer)
  1.1882 +    httpChannel->SetReferrer(mReferrer);
  1.1883 +  // convey the mAllowPipelining flag
  1.1884 +  httpChannel->SetAllowPipelining(mAllowPipelining);
  1.1885 +  // convey the new redirection limit
  1.1886 +  httpChannel->SetRedirectionLimit(mRedirectionLimit - 1);
  1.1887 +
  1.1888 +  // convey the Accept header value
  1.1889 +  {
  1.1890 +    nsAutoCString oldAcceptValue;
  1.1891 +    nsresult hasHeader = mRequestHead.GetHeader(nsHttp::Accept, oldAcceptValue);
  1.1892 +    if (NS_SUCCEEDED(hasHeader)) {
  1.1893 +      httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
  1.1894 +                                    oldAcceptValue,
  1.1895 +                                    false);
  1.1896 +    }
  1.1897 +  }
  1.1898 +
  1.1899 +  nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(newChannel);
  1.1900 +  if (httpInternal) {
  1.1901 +    // convey the mForceAllowThirdPartyCookie flag
  1.1902 +    httpInternal->SetForceAllowThirdPartyCookie(mForceAllowThirdPartyCookie);
  1.1903 +    // convey the spdy flag
  1.1904 +    httpInternal->SetAllowSpdy(mAllowSpdy);
  1.1905 +
  1.1906 +    // update the DocumentURI indicator since we are being redirected.
  1.1907 +    // if this was a top-level document channel, then the new channel
  1.1908 +    // should have its mDocumentURI point to newURI; otherwise, we
  1.1909 +    // just need to pass along our mDocumentURI to the new channel.
  1.1910 +    if (newURI && (mURI == mDocumentURI))
  1.1911 +      httpInternal->SetDocumentURI(newURI);
  1.1912 +    else
  1.1913 +      httpInternal->SetDocumentURI(mDocumentURI);
  1.1914 +
  1.1915 +    // if there is a chain of keys for redirect-responses we transfer it to
  1.1916 +    // the new channel (see bug #561276)
  1.1917 +    if (mRedirectedCachekeys) {
  1.1918 +        LOG(("HttpBaseChannel::SetupReplacementChannel "
  1.1919 +             "[this=%p] transferring chain of redirect cache-keys", this));
  1.1920 +        httpInternal->SetCacheKeysRedirectChain(mRedirectedCachekeys.forget());
  1.1921 +    }
  1.1922 +  }
  1.1923 +
  1.1924 +  // transfer application cache information
  1.1925 +  nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
  1.1926 +    do_QueryInterface(newChannel);
  1.1927 +  if (appCacheChannel) {
  1.1928 +    appCacheChannel->SetApplicationCache(mApplicationCache);
  1.1929 +    appCacheChannel->SetInheritApplicationCache(mInheritApplicationCache);
  1.1930 +    // We purposely avoid transfering mChooseApplicationCache.
  1.1931 +  }
  1.1932 +
  1.1933 +  // transfer any properties
  1.1934 +  nsCOMPtr<nsIWritablePropertyBag> bag(do_QueryInterface(newChannel));
  1.1935 +  if (bag)
  1.1936 +    mPropertyHash.EnumerateRead(CopyProperties, bag.get());
  1.1937 +
  1.1938 +  // Transfer the timing data (if we are dealing with an nsITimedChannel).
  1.1939 +  nsCOMPtr<nsITimedChannel> newTimedChannel(do_QueryInterface(newChannel));
  1.1940 +  nsCOMPtr<nsITimedChannel> oldTimedChannel(
  1.1941 +      do_QueryInterface(static_cast<nsIHttpChannel*>(this)));
  1.1942 +  if (oldTimedChannel && newTimedChannel) {
  1.1943 +    newTimedChannel->SetTimingEnabled(mTimingEnabled);
  1.1944 +    newTimedChannel->SetRedirectCount(mRedirectCount + 1);
  1.1945 +
  1.1946 +    // If the RedirectStart is null, we will use the AsyncOpen value of the
  1.1947 +    // previous channel (this is the first redirect in the redirects chain).
  1.1948 +    if (mRedirectStartTimeStamp.IsNull()) {
  1.1949 +      TimeStamp asyncOpen;
  1.1950 +      oldTimedChannel->GetAsyncOpen(&asyncOpen);
  1.1951 +      newTimedChannel->SetRedirectStart(asyncOpen);
  1.1952 +    }
  1.1953 +    else {
  1.1954 +      newTimedChannel->SetRedirectStart(mRedirectStartTimeStamp);
  1.1955 +    }
  1.1956 +
  1.1957 +    // The RedirectEnd timestamp is equal to the previous channel response end.
  1.1958 +    TimeStamp prevResponseEnd;
  1.1959 +    oldTimedChannel->GetResponseEnd(&prevResponseEnd);
  1.1960 +    newTimedChannel->SetRedirectEnd(prevResponseEnd);
  1.1961 +
  1.1962 +    // Check whether or not this was a cross-domain redirect.
  1.1963 +    newTimedChannel->SetAllRedirectsSameOrigin(
  1.1964 +        mAllRedirectsSameOrigin && SameOriginWithOriginalUri(newURI));
  1.1965 +  }
  1.1966 +
  1.1967 +  return NS_OK;
  1.1968 +}
  1.1969 +
  1.1970 +// Redirect Tracking
  1.1971 +bool
  1.1972 +HttpBaseChannel::SameOriginWithOriginalUri(nsIURI *aURI)
  1.1973 +{
  1.1974 +  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
  1.1975 +  nsresult rv = ssm->CheckSameOriginURI(aURI, mOriginalURI, false);
  1.1976 +  return (NS_SUCCEEDED(rv));
  1.1977 +}
  1.1978 +
  1.1979 +
  1.1980 +
  1.1981 +//-----------------------------------------------------------------------------
  1.1982 +// HttpBaseChannel::nsITimedChannel
  1.1983 +//-----------------------------------------------------------------------------
  1.1984 +
  1.1985 +NS_IMETHODIMP
  1.1986 +HttpBaseChannel::SetTimingEnabled(bool enabled) {
  1.1987 +  mTimingEnabled = enabled;
  1.1988 +  return NS_OK;
  1.1989 +}
  1.1990 +
  1.1991 +NS_IMETHODIMP
  1.1992 +HttpBaseChannel::GetTimingEnabled(bool* _retval) {
  1.1993 +  *_retval = mTimingEnabled;
  1.1994 +  return NS_OK;
  1.1995 +}
  1.1996 +
  1.1997 +NS_IMETHODIMP
  1.1998 +HttpBaseChannel::GetChannelCreation(TimeStamp* _retval) {
  1.1999 +  *_retval = mChannelCreationTimestamp;
  1.2000 +  return NS_OK;
  1.2001 +}
  1.2002 +
  1.2003 +NS_IMETHODIMP
  1.2004 +HttpBaseChannel::GetAsyncOpen(TimeStamp* _retval) {
  1.2005 +  *_retval = mAsyncOpenTime;
  1.2006 +  return NS_OK;
  1.2007 +}
  1.2008 +
  1.2009 +/**
  1.2010 + * @return the number of redirects. There is no check for cross-domain
  1.2011 + * redirects. This check must be done by the consumers.
  1.2012 + */
  1.2013 +NS_IMETHODIMP
  1.2014 +HttpBaseChannel::GetRedirectCount(uint16_t *aRedirectCount)
  1.2015 +{
  1.2016 +  *aRedirectCount = mRedirectCount;
  1.2017 +  return NS_OK;
  1.2018 +}
  1.2019 +
  1.2020 +NS_IMETHODIMP
  1.2021 +HttpBaseChannel::SetRedirectCount(uint16_t aRedirectCount)
  1.2022 +{
  1.2023 +  mRedirectCount = aRedirectCount;
  1.2024 +  return NS_OK;
  1.2025 +}
  1.2026 +
  1.2027 +NS_IMETHODIMP
  1.2028 +HttpBaseChannel::GetRedirectStart(TimeStamp* _retval)
  1.2029 +{
  1.2030 +  *_retval = mRedirectStartTimeStamp;
  1.2031 +  return NS_OK;
  1.2032 +}
  1.2033 +
  1.2034 +NS_IMETHODIMP
  1.2035 +HttpBaseChannel::SetRedirectStart(TimeStamp aRedirectStart)
  1.2036 +{
  1.2037 +  mRedirectStartTimeStamp = aRedirectStart;
  1.2038 +  return NS_OK;
  1.2039 +}
  1.2040 +
  1.2041 +NS_IMETHODIMP
  1.2042 +HttpBaseChannel::GetRedirectEnd(TimeStamp* _retval)
  1.2043 +{
  1.2044 +  *_retval = mRedirectEndTimeStamp;
  1.2045 +  return NS_OK;
  1.2046 +}
  1.2047 +
  1.2048 +NS_IMETHODIMP
  1.2049 +HttpBaseChannel::SetRedirectEnd(TimeStamp aRedirectEnd)
  1.2050 +{
  1.2051 +  mRedirectEndTimeStamp = aRedirectEnd;
  1.2052 +  return NS_OK;
  1.2053 +}
  1.2054 +
  1.2055 +NS_IMETHODIMP
  1.2056 +HttpBaseChannel::GetAllRedirectsSameOrigin(bool *aAllRedirectsSameOrigin)
  1.2057 +{
  1.2058 +  *aAllRedirectsSameOrigin = mAllRedirectsSameOrigin;
  1.2059 +  return NS_OK;
  1.2060 +}
  1.2061 +
  1.2062 +NS_IMETHODIMP
  1.2063 +HttpBaseChannel::SetAllRedirectsSameOrigin(bool aAllRedirectsSameOrigin)
  1.2064 +{
  1.2065 +  mAllRedirectsSameOrigin = aAllRedirectsSameOrigin;
  1.2066 +  return NS_OK;
  1.2067 +}
  1.2068 +
  1.2069 +NS_IMETHODIMP
  1.2070 +HttpBaseChannel::GetDomainLookupStart(TimeStamp* _retval) {
  1.2071 +  *_retval = mTransactionTimings.domainLookupStart;
  1.2072 +  return NS_OK;
  1.2073 +}
  1.2074 +
  1.2075 +NS_IMETHODIMP
  1.2076 +HttpBaseChannel::GetDomainLookupEnd(TimeStamp* _retval) {
  1.2077 +  *_retval = mTransactionTimings.domainLookupEnd;
  1.2078 +  return NS_OK;
  1.2079 +}
  1.2080 +
  1.2081 +NS_IMETHODIMP
  1.2082 +HttpBaseChannel::GetConnectStart(TimeStamp* _retval) {
  1.2083 +  *_retval = mTransactionTimings.connectStart;
  1.2084 +  return NS_OK;
  1.2085 +}
  1.2086 +
  1.2087 +NS_IMETHODIMP
  1.2088 +HttpBaseChannel::GetConnectEnd(TimeStamp* _retval) {
  1.2089 +  *_retval = mTransactionTimings.connectEnd;
  1.2090 +  return NS_OK;
  1.2091 +}
  1.2092 +
  1.2093 +NS_IMETHODIMP
  1.2094 +HttpBaseChannel::GetRequestStart(TimeStamp* _retval) {
  1.2095 +  *_retval = mTransactionTimings.requestStart;
  1.2096 +  return NS_OK;
  1.2097 +}
  1.2098 +
  1.2099 +NS_IMETHODIMP
  1.2100 +HttpBaseChannel::GetResponseStart(TimeStamp* _retval) {
  1.2101 +  *_retval = mTransactionTimings.responseStart;
  1.2102 +  return NS_OK;
  1.2103 +}
  1.2104 +
  1.2105 +NS_IMETHODIMP
  1.2106 +HttpBaseChannel::GetResponseEnd(TimeStamp* _retval) {
  1.2107 +  *_retval = mTransactionTimings.responseEnd;
  1.2108 +  return NS_OK;
  1.2109 +}
  1.2110 +
  1.2111 +NS_IMETHODIMP
  1.2112 +HttpBaseChannel::GetCacheReadStart(TimeStamp* _retval) {
  1.2113 +  *_retval = mCacheReadStart;
  1.2114 +  return NS_OK;
  1.2115 +}
  1.2116 +
  1.2117 +NS_IMETHODIMP
  1.2118 +HttpBaseChannel::GetCacheReadEnd(TimeStamp* _retval) {
  1.2119 +  *_retval = mCacheReadEnd;
  1.2120 +  return NS_OK;
  1.2121 +}
  1.2122 +
  1.2123 +NS_IMETHODIMP
  1.2124 +HttpBaseChannel::GetInitiatorType(nsAString & aInitiatorType)
  1.2125 +{
  1.2126 +  aInitiatorType = mInitiatorType;
  1.2127 +  return NS_OK;
  1.2128 +}
  1.2129 +
  1.2130 +NS_IMETHODIMP
  1.2131 +HttpBaseChannel::SetInitiatorType(const nsAString & aInitiatorType)
  1.2132 +{
  1.2133 +  mInitiatorType = aInitiatorType;
  1.2134 +  return NS_OK;
  1.2135 +}
  1.2136 +
  1.2137 +#define IMPL_TIMING_ATTR(name)                                 \
  1.2138 +NS_IMETHODIMP                                                  \
  1.2139 +HttpBaseChannel::Get##name##Time(PRTime* _retval) {            \
  1.2140 +    TimeStamp stamp;                                           \
  1.2141 +    Get##name(&stamp);                                         \
  1.2142 +    if (stamp.IsNull()) {                                      \
  1.2143 +        *_retval = 0;                                          \
  1.2144 +        return NS_OK;                                          \
  1.2145 +    }                                                          \
  1.2146 +    *_retval = mChannelCreationTime +                          \
  1.2147 +        (PRTime) ((stamp - mChannelCreationTimestamp).ToSeconds() * 1e6); \
  1.2148 +    return NS_OK;                                              \
  1.2149 +}
  1.2150 +
  1.2151 +IMPL_TIMING_ATTR(ChannelCreation)
  1.2152 +IMPL_TIMING_ATTR(AsyncOpen)
  1.2153 +IMPL_TIMING_ATTR(DomainLookupStart)
  1.2154 +IMPL_TIMING_ATTR(DomainLookupEnd)
  1.2155 +IMPL_TIMING_ATTR(ConnectStart)
  1.2156 +IMPL_TIMING_ATTR(ConnectEnd)
  1.2157 +IMPL_TIMING_ATTR(RequestStart)
  1.2158 +IMPL_TIMING_ATTR(ResponseStart)
  1.2159 +IMPL_TIMING_ATTR(ResponseEnd)
  1.2160 +IMPL_TIMING_ATTR(CacheReadStart)
  1.2161 +IMPL_TIMING_ATTR(CacheReadEnd)
  1.2162 +IMPL_TIMING_ATTR(RedirectStart)
  1.2163 +IMPL_TIMING_ATTR(RedirectEnd)
  1.2164 +
  1.2165 +#undef IMPL_TIMING_ATTR
  1.2166 +
  1.2167 +
  1.2168 +//------------------------------------------------------------------------------
  1.2169 +
  1.2170 +}  // namespace net
  1.2171 +}  // namespace mozilla
  1.2172 +

mercurial