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 +