netwerk/protocol/http/HttpBaseChannel.cpp

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

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

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

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

mercurial