dom/base/nsPerformance.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/base/nsPerformance.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,579 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsPerformance.h"
    1.10 +#include "nsCOMPtr.h"
    1.11 +#include "nsIHttpChannel.h"
    1.12 +#include "nsITimedChannel.h"
    1.13 +#include "nsDOMNavigationTiming.h"
    1.14 +#include "nsContentUtils.h"
    1.15 +#include "nsIScriptSecurityManager.h"
    1.16 +#include "nsIDOMWindow.h"
    1.17 +#include "nsIURI.h"
    1.18 +#include "PerformanceEntry.h"
    1.19 +#include "PerformanceResourceTiming.h"
    1.20 +#include "mozilla/dom/PerformanceBinding.h"
    1.21 +#include "mozilla/dom/PerformanceTimingBinding.h"
    1.22 +#include "mozilla/dom/PerformanceNavigationBinding.h"
    1.23 +#include "mozilla/TimeStamp.h"
    1.24 +#include "nsThreadUtils.h"
    1.25 +
    1.26 +using namespace mozilla;
    1.27 +
    1.28 +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsPerformanceTiming, mPerformance)
    1.29 +
    1.30 +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsPerformanceTiming, AddRef)
    1.31 +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsPerformanceTiming, Release)
    1.32 +
    1.33 +nsPerformanceTiming::nsPerformanceTiming(nsPerformance* aPerformance,
    1.34 +                                         nsITimedChannel* aChannel,
    1.35 +                                         nsIHttpChannel* aHttpChannel,
    1.36 +                                         DOMHighResTimeStamp aZeroTime)
    1.37 +  : mPerformance(aPerformance),
    1.38 +    mChannel(aChannel),
    1.39 +    mFetchStart(0.0),
    1.40 +    mZeroTime(aZeroTime),
    1.41 +    mReportCrossOriginResources(true)
    1.42 +{
    1.43 +  MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
    1.44 +  SetIsDOMBinding();
    1.45 +
    1.46 +  if (!nsContentUtils::IsPerformanceTimingEnabled()) {
    1.47 +    mZeroTime = 0;
    1.48 +  }
    1.49 +
    1.50 + // The aHttpChannel argument is null if this nsPerformanceTiming object
    1.51 +  // is being used for the navigation timing (document) and has a non-null
    1.52 +  // value for the resource timing (any resources within the page).
    1.53 +  if (aHttpChannel) {
    1.54 +    CheckRedirectCrossOrigin(aHttpChannel);
    1.55 +  }
    1.56 +}
    1.57 +
    1.58 +nsPerformanceTiming::~nsPerformanceTiming()
    1.59 +{
    1.60 +}
    1.61 +
    1.62 +DOMHighResTimeStamp
    1.63 +nsPerformanceTiming::FetchStartHighRes()
    1.64 +{
    1.65 +  if (!mFetchStart) {
    1.66 +    if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
    1.67 +      return mZeroTime;
    1.68 +    }
    1.69 +    TimeStamp stamp;
    1.70 +    mChannel->GetAsyncOpen(&stamp);
    1.71 +    MOZ_ASSERT(!stamp.IsNull(), "The fetch start time stamp should always be "
    1.72 +        "valid if the performance timing is enabled");
    1.73 +    mFetchStart = (!stamp.IsNull())
    1.74 +        ? TimeStampToDOMHighRes(stamp)
    1.75 +        : 0.0;
    1.76 +  }
    1.77 +  return mFetchStart;
    1.78 +}
    1.79 +
    1.80 +DOMTimeMilliSec
    1.81 +nsPerformanceTiming::FetchStart()
    1.82 +{
    1.83 +  return static_cast<int64_t>(FetchStartHighRes());
    1.84 +}
    1.85 +
    1.86 +// This method will implement the timing allow check algorithm
    1.87 +// http://w3c-test.org/webperf/specs/ResourceTiming/#timing-allow-check
    1.88 +// https://bugzilla.mozilla.org/show_bug.cgi?id=936814
    1.89 +void
    1.90 +nsPerformanceTiming::CheckRedirectCrossOrigin(nsIHttpChannel* aResourceChannel)
    1.91 +{
    1.92 +  if (!IsInitialized()) {
    1.93 +    return;
    1.94 +  }
    1.95 +  uint16_t redirectCount;
    1.96 +  mChannel->GetRedirectCount(&redirectCount);
    1.97 +  if (redirectCount == 0) {
    1.98 +    return;
    1.99 +  }
   1.100 +  nsCOMPtr<nsIURI> resourceURI, referrerURI;
   1.101 +  aResourceChannel->GetReferrer(getter_AddRefs(referrerURI));
   1.102 +  aResourceChannel->GetURI(getter_AddRefs(resourceURI));
   1.103 +  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   1.104 +  nsresult rv = ssm->CheckSameOriginURI(resourceURI, referrerURI, false);
   1.105 +  if (!NS_SUCCEEDED(rv)) {
   1.106 +    mReportCrossOriginResources = false;
   1.107 +  }
   1.108 +}
   1.109 +
   1.110 +bool
   1.111 +nsPerformanceTiming::IsSameOriginAsReferral() const
   1.112 +{
   1.113 +  return mReportCrossOriginResources;
   1.114 +}
   1.115 +
   1.116 +uint16_t
   1.117 +nsPerformanceTiming::GetRedirectCount() const
   1.118 +{
   1.119 +  if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
   1.120 +    return 0;
   1.121 +  }
   1.122 +  bool sameOrigin;
   1.123 +  mChannel->GetAllRedirectsSameOrigin(&sameOrigin);
   1.124 +  if (!sameOrigin) {
   1.125 +    return 0;
   1.126 +  }
   1.127 +  uint16_t redirectCount;
   1.128 +  mChannel->GetRedirectCount(&redirectCount);
   1.129 +  return redirectCount;
   1.130 +}
   1.131 +
   1.132 +/**
   1.133 + * RedirectStartHighRes() is used by both the navigation timing and the
   1.134 + * resource timing. Since, navigation timing and resource timing check and
   1.135 + * interpret cross-domain redirects in a different manner,
   1.136 + * RedirectStartHighRes() will make no checks for cross-domain redirect.
   1.137 + * It's up to the consumers of this method (nsPerformanceTiming::RedirectStart()
   1.138 + * and PerformanceResourceTiming::RedirectStart() to make such verifications.
   1.139 + *
   1.140 + * @return a valid timing if the Performance Timing is enabled
   1.141 + */
   1.142 +DOMHighResTimeStamp
   1.143 +nsPerformanceTiming::RedirectStartHighRes()
   1.144 +{
   1.145 +  if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
   1.146 +    return mZeroTime;
   1.147 +  }
   1.148 +  mozilla::TimeStamp stamp;
   1.149 +  mChannel->GetRedirectStart(&stamp);
   1.150 +  return TimeStampToDOMHighResOrFetchStart(stamp);
   1.151 +}
   1.152 +
   1.153 +DOMTimeMilliSec
   1.154 +nsPerformanceTiming::RedirectStart()
   1.155 +{
   1.156 +  if (!IsInitialized()) {
   1.157 +    return mZeroTime;
   1.158 +  }
   1.159 +  // We have to check if all the redirect URIs had the same origin (since there
   1.160 +  // is no check in RedirectStartHighRes())
   1.161 +  bool sameOrigin;
   1.162 +  mChannel->GetAllRedirectsSameOrigin(&sameOrigin);
   1.163 +  if (sameOrigin) {
   1.164 +    return static_cast<int64_t>(RedirectStartHighRes());
   1.165 +  }
   1.166 +  return 0;
   1.167 +}
   1.168 +
   1.169 +/**
   1.170 + * RedirectEndHighRes() is used by both the navigation timing and the resource
   1.171 + * timing. Since, navigation timing and resource timing check and interpret
   1.172 + * cross-domain redirects in a different manner, RedirectEndHighRes() will make
   1.173 + * no checks for cross-domain redirect. It's up to the consumers of this method
   1.174 + * (nsPerformanceTiming::RedirectEnd() and
   1.175 + * PerformanceResourceTiming::RedirectEnd() to make such verifications.
   1.176 + *
   1.177 + * @return a valid timing if the Performance Timing is enabled
   1.178 + */
   1.179 +DOMHighResTimeStamp
   1.180 +nsPerformanceTiming::RedirectEndHighRes()
   1.181 +{
   1.182 +  if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
   1.183 +    return mZeroTime;
   1.184 +  }
   1.185 +  mozilla::TimeStamp stamp;
   1.186 +  mChannel->GetRedirectEnd(&stamp);
   1.187 +  return TimeStampToDOMHighResOrFetchStart(stamp);
   1.188 +}
   1.189 +
   1.190 +DOMTimeMilliSec
   1.191 +nsPerformanceTiming::RedirectEnd()
   1.192 +{
   1.193 +  if (!IsInitialized()) {
   1.194 +    return mZeroTime;
   1.195 +  }
   1.196 +  // We have to check if all the redirect URIs had the same origin (since there
   1.197 +  // is no check in RedirectEndHighRes())
   1.198 +  bool sameOrigin;
   1.199 +  mChannel->GetAllRedirectsSameOrigin(&sameOrigin);
   1.200 +  if (sameOrigin) {
   1.201 +    return static_cast<int64_t>(RedirectEndHighRes());
   1.202 +  }
   1.203 +  return 0;
   1.204 +}
   1.205 +
   1.206 +DOMHighResTimeStamp
   1.207 +nsPerformanceTiming::DomainLookupStartHighRes()
   1.208 +{
   1.209 +  if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
   1.210 +    return mZeroTime;
   1.211 +  }
   1.212 +  mozilla::TimeStamp stamp;
   1.213 +  mChannel->GetDomainLookupStart(&stamp);
   1.214 +  return TimeStampToDOMHighResOrFetchStart(stamp);
   1.215 +}
   1.216 +
   1.217 +DOMTimeMilliSec
   1.218 +nsPerformanceTiming::DomainLookupStart()
   1.219 +{
   1.220 +  return static_cast<int64_t>(DomainLookupStartHighRes());
   1.221 +}
   1.222 +
   1.223 +DOMHighResTimeStamp
   1.224 +nsPerformanceTiming::DomainLookupEndHighRes()
   1.225 +{
   1.226 +  if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
   1.227 +    return mZeroTime;
   1.228 +  }
   1.229 +  mozilla::TimeStamp stamp;
   1.230 +  mChannel->GetDomainLookupEnd(&stamp);
   1.231 +  return TimeStampToDOMHighResOrFetchStart(stamp);
   1.232 +}
   1.233 +
   1.234 +DOMTimeMilliSec
   1.235 +nsPerformanceTiming::DomainLookupEnd()
   1.236 +{
   1.237 +  return static_cast<int64_t>(DomainLookupEndHighRes());
   1.238 +}
   1.239 +
   1.240 +DOMHighResTimeStamp
   1.241 +nsPerformanceTiming::ConnectStartHighRes()
   1.242 +{
   1.243 +  if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
   1.244 +    return mZeroTime;
   1.245 +  }
   1.246 +  mozilla::TimeStamp stamp;
   1.247 +  mChannel->GetConnectStart(&stamp);
   1.248 +  return TimeStampToDOMHighResOrFetchStart(stamp);
   1.249 +}
   1.250 +
   1.251 +DOMTimeMilliSec
   1.252 +nsPerformanceTiming::ConnectStart()
   1.253 +{
   1.254 +  return static_cast<int64_t>(ConnectStartHighRes());
   1.255 +}
   1.256 +
   1.257 +DOMHighResTimeStamp
   1.258 +nsPerformanceTiming::ConnectEndHighRes()
   1.259 +{
   1.260 +  if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
   1.261 +    return mZeroTime;
   1.262 +  }
   1.263 +  mozilla::TimeStamp stamp;
   1.264 +  mChannel->GetConnectEnd(&stamp);
   1.265 +  return TimeStampToDOMHighResOrFetchStart(stamp);
   1.266 +}
   1.267 +
   1.268 +DOMTimeMilliSec
   1.269 +nsPerformanceTiming::ConnectEnd()
   1.270 +{
   1.271 +  return static_cast<int64_t>(ConnectEndHighRes());
   1.272 +}
   1.273 +
   1.274 +DOMHighResTimeStamp
   1.275 +nsPerformanceTiming::RequestStartHighRes()
   1.276 +{
   1.277 +  if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
   1.278 +    return mZeroTime;
   1.279 +  }
   1.280 +  mozilla::TimeStamp stamp;
   1.281 +  mChannel->GetRequestStart(&stamp);
   1.282 +  return TimeStampToDOMHighResOrFetchStart(stamp);
   1.283 +}
   1.284 +
   1.285 +DOMTimeMilliSec
   1.286 +nsPerformanceTiming::RequestStart()
   1.287 +{
   1.288 +  return static_cast<int64_t>(RequestStartHighRes());
   1.289 +}
   1.290 +
   1.291 +DOMHighResTimeStamp
   1.292 +nsPerformanceTiming::ResponseStartHighRes()
   1.293 +{
   1.294 +  if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
   1.295 +    return mZeroTime;
   1.296 +  }
   1.297 +  mozilla::TimeStamp stamp;
   1.298 +  mChannel->GetResponseStart(&stamp);
   1.299 +  mozilla::TimeStamp cacheStamp;
   1.300 +  mChannel->GetCacheReadStart(&cacheStamp);
   1.301 +  if (stamp.IsNull() || (!cacheStamp.IsNull() && cacheStamp < stamp)) {
   1.302 +    stamp = cacheStamp;
   1.303 +  }
   1.304 +  return TimeStampToDOMHighResOrFetchStart(stamp);
   1.305 +}
   1.306 +
   1.307 +DOMTimeMilliSec
   1.308 +nsPerformanceTiming::ResponseStart()
   1.309 +{
   1.310 +  return static_cast<int64_t>(ResponseStartHighRes());
   1.311 +}
   1.312 +
   1.313 +DOMHighResTimeStamp
   1.314 +nsPerformanceTiming::ResponseEndHighRes()
   1.315 +{
   1.316 +  if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) {
   1.317 +    return mZeroTime;
   1.318 +  }
   1.319 +  mozilla::TimeStamp stamp;
   1.320 +  mChannel->GetResponseEnd(&stamp);
   1.321 +  mozilla::TimeStamp cacheStamp;
   1.322 +  mChannel->GetCacheReadEnd(&cacheStamp);
   1.323 +  if (stamp.IsNull() || (!cacheStamp.IsNull() && cacheStamp < stamp)) {
   1.324 +    stamp = cacheStamp;
   1.325 +  }
   1.326 +  return TimeStampToDOMHighResOrFetchStart(stamp);
   1.327 +}
   1.328 +
   1.329 +DOMTimeMilliSec
   1.330 +nsPerformanceTiming::ResponseEnd()
   1.331 +{
   1.332 +  return static_cast<int64_t>(ResponseEndHighRes());
   1.333 +}
   1.334 +
   1.335 +bool
   1.336 +nsPerformanceTiming::IsInitialized() const
   1.337 +{
   1.338 +  return !!mChannel;
   1.339 +}
   1.340 +
   1.341 +JSObject*
   1.342 +nsPerformanceTiming::WrapObject(JSContext *cx)
   1.343 +{
   1.344 +  return dom::PerformanceTimingBinding::Wrap(cx, this);
   1.345 +}
   1.346 +
   1.347 +
   1.348 +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsPerformanceNavigation, mPerformance)
   1.349 +
   1.350 +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsPerformanceNavigation, AddRef)
   1.351 +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsPerformanceNavigation, Release)
   1.352 +
   1.353 +nsPerformanceNavigation::nsPerformanceNavigation(nsPerformance* aPerformance)
   1.354 +  : mPerformance(aPerformance)
   1.355 +{
   1.356 +  MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
   1.357 +  SetIsDOMBinding();
   1.358 +}
   1.359 +
   1.360 +nsPerformanceNavigation::~nsPerformanceNavigation()
   1.361 +{
   1.362 +}
   1.363 +
   1.364 +JSObject*
   1.365 +nsPerformanceNavigation::WrapObject(JSContext *cx)
   1.366 +{
   1.367 +  return dom::PerformanceNavigationBinding::Wrap(cx, this);
   1.368 +}
   1.369 +
   1.370 +
   1.371 +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_5(nsPerformance,
   1.372 +                                        mWindow, mTiming,
   1.373 +                                        mNavigation, mEntries,
   1.374 +                                        mParentPerformance)
   1.375 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPerformance)
   1.376 +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPerformance)
   1.377 +
   1.378 +nsPerformance::nsPerformance(nsIDOMWindow* aWindow,
   1.379 +                             nsDOMNavigationTiming* aDOMTiming,
   1.380 +                             nsITimedChannel* aChannel,
   1.381 +                             nsPerformance* aParentPerformance)
   1.382 +  : mWindow(aWindow),
   1.383 +    mDOMTiming(aDOMTiming),
   1.384 +    mChannel(aChannel),
   1.385 +    mParentPerformance(aParentPerformance),
   1.386 +    mBufferSizeSet(kDefaultBufferSize),
   1.387 +    mPrimaryBufferSize(kDefaultBufferSize)
   1.388 +{
   1.389 +  MOZ_ASSERT(aWindow, "Parent window object should be provided");
   1.390 +  SetIsDOMBinding();
   1.391 +}
   1.392 +
   1.393 +nsPerformance::~nsPerformance()
   1.394 +{
   1.395 +}
   1.396 +
   1.397 +// QueryInterface implementation for nsPerformance
   1.398 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPerformance)
   1.399 +  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   1.400 +  NS_INTERFACE_MAP_ENTRY(nsISupports)
   1.401 +NS_INTERFACE_MAP_END
   1.402 +
   1.403 +
   1.404 +nsPerformanceTiming*
   1.405 +nsPerformance::Timing()
   1.406 +{
   1.407 +  if (!mTiming) {
   1.408 +    // For navigation timing, the third argument (an nsIHtttpChannel) is null
   1.409 +    // since the cross-domain redirect were already checked.
   1.410 +    // The last argument (zero time) for performance.timing is the navigation
   1.411 +    // start value.
   1.412 +    mTiming = new nsPerformanceTiming(this, mChannel, nullptr,
   1.413 +        mDOMTiming->GetNavigationStart());
   1.414 +  }
   1.415 +  return mTiming;
   1.416 +}
   1.417 +
   1.418 +nsPerformanceNavigation*
   1.419 +nsPerformance::Navigation()
   1.420 +{
   1.421 +  if (!mNavigation) {
   1.422 +    mNavigation = new nsPerformanceNavigation(this);
   1.423 +  }
   1.424 +  return mNavigation;
   1.425 +}
   1.426 +
   1.427 +DOMHighResTimeStamp
   1.428 +nsPerformance::Now()
   1.429 +{
   1.430 +  return GetDOMTiming()->TimeStampToDOMHighRes(mozilla::TimeStamp::Now());
   1.431 +}
   1.432 +
   1.433 +JSObject*
   1.434 +nsPerformance::WrapObject(JSContext *cx)
   1.435 +{
   1.436 +  return dom::PerformanceBinding::Wrap(cx, this);
   1.437 +}
   1.438 +
   1.439 +void
   1.440 +nsPerformance::GetEntries(nsTArray<nsRefPtr<PerformanceEntry> >& retval)
   1.441 +{
   1.442 +  MOZ_ASSERT(NS_IsMainThread());
   1.443 +
   1.444 +  retval.Clear();
   1.445 +  uint32_t count = mEntries.Length();
   1.446 +  if (count > mPrimaryBufferSize) {
   1.447 +    count = mPrimaryBufferSize;
   1.448 +  }
   1.449 +  retval.AppendElements(mEntries.Elements(), count);
   1.450 +}
   1.451 +
   1.452 +void
   1.453 +nsPerformance::GetEntriesByType(const nsAString& entryType,
   1.454 +                                nsTArray<nsRefPtr<PerformanceEntry> >& retval)
   1.455 +{
   1.456 +  MOZ_ASSERT(NS_IsMainThread());
   1.457 +
   1.458 +  retval.Clear();
   1.459 +  uint32_t count = mEntries.Length();
   1.460 +  for (uint32_t i = 0 ; i < count && i < mPrimaryBufferSize ; i++) {
   1.461 +    if (mEntries[i]->GetEntryType().Equals(entryType)) {
   1.462 +      retval.AppendElement(mEntries[i]);
   1.463 +    }
   1.464 +  }
   1.465 +}
   1.466 +
   1.467 +void
   1.468 +nsPerformance::GetEntriesByName(const nsAString& name,
   1.469 +                                const mozilla::dom::Optional<nsAString>& entryType,
   1.470 +                                nsTArray<nsRefPtr<PerformanceEntry> >& retval)
   1.471 +{
   1.472 +  MOZ_ASSERT(NS_IsMainThread());
   1.473 +
   1.474 +  retval.Clear();
   1.475 +  uint32_t count = mEntries.Length();
   1.476 +  for (uint32_t i = 0 ; i < count && i < mPrimaryBufferSize ; i++) {
   1.477 +    if (mEntries[i]->GetName().Equals(name) &&
   1.478 +        (!entryType.WasPassed() ||
   1.479 +         mEntries[i]->GetEntryType().Equals(entryType.Value()))) {
   1.480 +      retval.AppendElement(mEntries[i]);
   1.481 +    }
   1.482 +  }
   1.483 +}
   1.484 +
   1.485 +void
   1.486 +nsPerformance::ClearResourceTimings()
   1.487 +{
   1.488 +  MOZ_ASSERT(NS_IsMainThread());
   1.489 +  mPrimaryBufferSize = mBufferSizeSet;
   1.490 +  mEntries.Clear();
   1.491 +}
   1.492 +
   1.493 +void
   1.494 +nsPerformance::SetResourceTimingBufferSize(uint64_t maxSize)
   1.495 +{
   1.496 +  MOZ_ASSERT(NS_IsMainThread());
   1.497 +  mBufferSizeSet = maxSize;
   1.498 +  if (mBufferSizeSet < mEntries.Length()) {
   1.499 +    // call onresourcetimingbufferfull
   1.500 +    // https://bugzilla.mozilla.org/show_bug.cgi?id=936813
   1.501 +  }
   1.502 +}
   1.503 +
   1.504 +/**
   1.505 + * An entry should be added only after the resource is loaded.
   1.506 + * This method is not thread safe and can only be called on the main thread.
   1.507 + */
   1.508 +void
   1.509 +nsPerformance::AddEntry(nsIHttpChannel* channel,
   1.510 +                        nsITimedChannel* timedChannel)
   1.511 +{
   1.512 +  MOZ_ASSERT(NS_IsMainThread());
   1.513 +  // Check if resource timing is prefed off.
   1.514 +  if (!nsContentUtils::IsResourceTimingEnabled()) {
   1.515 +    return;
   1.516 +  }
   1.517 +  if (channel && timedChannel) {
   1.518 +    nsAutoCString name;
   1.519 +    nsAutoString initiatorType;
   1.520 +    nsCOMPtr<nsIURI> originalURI;
   1.521 +
   1.522 +    timedChannel->GetInitiatorType(initiatorType);
   1.523 +
   1.524 +    // According to the spec, "The name attribute must return the resolved URL
   1.525 +    // of the requested resource. This attribute must not change even if the
   1.526 +    // fetch redirected to a different URL."
   1.527 +    channel->GetOriginalURI(getter_AddRefs(originalURI));
   1.528 +    originalURI->GetSpec(name);
   1.529 +    NS_ConvertUTF8toUTF16 entryName(name);
   1.530 +
   1.531 +    // The nsITimedChannel argument will be used to gather all the timings.
   1.532 +    // The nsIHttpChannel argument will be used to check if any cross-origin
   1.533 +    // redirects occurred.
   1.534 +    // The last argument is the "zero time" (offset). Since we don't want
   1.535 +    // any offset for the resource timing, this will be set to "0" - the
   1.536 +    // resource timing returns a relative timing (no offset).
   1.537 +    nsRefPtr<nsPerformanceTiming> performanceTiming =
   1.538 +        new nsPerformanceTiming(this, timedChannel, channel,
   1.539 +            0);
   1.540 +
   1.541 +    // The PerformanceResourceTiming object will use the nsPerformanceTiming
   1.542 +    // object to get all the required timings.
   1.543 +    nsRefPtr<dom::PerformanceResourceTiming> performanceEntry =
   1.544 +        new dom::PerformanceResourceTiming(performanceTiming, this);
   1.545 +
   1.546 +    performanceEntry->SetName(entryName);
   1.547 +    performanceEntry->SetEntryType(NS_LITERAL_STRING("resource"));
   1.548 +    // If the initiator type had no valid value, then set it to the default
   1.549 +    // ("other") value.
   1.550 +    if (initiatorType.IsEmpty()) {
   1.551 +      initiatorType = NS_LITERAL_STRING("other");
   1.552 +    }
   1.553 +    performanceEntry->SetInitiatorType(initiatorType);
   1.554 +
   1.555 +    mEntries.InsertElementSorted(performanceEntry,
   1.556 +        PerformanceEntryComparator());
   1.557 +    if (mEntries.Length() > mPrimaryBufferSize) {
   1.558 +      // call onresourcetimingbufferfull
   1.559 +      // https://bugzilla.mozilla.org/show_bug.cgi?id=936813
   1.560 +    }
   1.561 +  }
   1.562 +}
   1.563 +
   1.564 +bool
   1.565 +nsPerformance::PerformanceEntryComparator::Equals(
   1.566 +    const PerformanceEntry* aElem1,
   1.567 +    const PerformanceEntry* aElem2) const
   1.568 +{
   1.569 +  NS_ABORT_IF_FALSE(aElem1 && aElem2,
   1.570 +      "Trying to compare null performance entries");
   1.571 +  return aElem1->StartTime() == aElem2->StartTime();
   1.572 +}
   1.573 +
   1.574 +bool
   1.575 +nsPerformance::PerformanceEntryComparator::LessThan(
   1.576 +    const PerformanceEntry* aElem1,
   1.577 +    const PerformanceEntry* aElem2) const
   1.578 +{
   1.579 +  NS_ABORT_IF_FALSE(aElem1 && aElem2,
   1.580 +      "Trying to compare null performance entries");
   1.581 +  return aElem1->StartTime() < aElem2->StartTime();
   1.582 +}

mercurial