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