Home | History | Annotate | Download | only in timing
      1 /*
      2  * Copyright (C) 2010 Google Inc. All rights reserved.
      3  * Copyright (C) 2012 Intel Inc. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  *     * Redistributions of source code must retain the above copyright
     10  * notice, this list of conditions and the following disclaimer.
     11  *     * Redistributions in binary form must reproduce the above
     12  * copyright notice, this list of conditions and the following disclaimer
     13  * in the documentation and/or other materials provided with the
     14  * distribution.
     15  *     * Neither the name of Google Inc. nor the names of its
     16  * contributors may be used to endorse or promote products derived from
     17  * this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include "config.h"
     33 #include "core/timing/Performance.h"
     34 
     35 #include "core/dom/Document.h"
     36 #include "core/frame/LocalFrame.h"
     37 #include "core/loader/DocumentLoader.h"
     38 #include "core/timing/ResourceTimingInfo.h"
     39 #include "core/timing/PerformanceResourceTiming.h"
     40 #include "core/timing/PerformanceUserTiming.h"
     41 #include "platform/weborigin/SecurityOrigin.h"
     42 #include "wtf/CurrentTime.h"
     43 
     44 namespace blink {
     45 
     46 static const size_t defaultResourceTimingBufferSize = 150;
     47 
     48 Performance::Performance(LocalFrame* frame)
     49     : DOMWindowProperty(frame)
     50     , m_resourceTimingBufferSize(defaultResourceTimingBufferSize)
     51     , m_referenceTime(frame && frame->host() ? frame->document()->loader()->timing()->referenceMonotonicTime() : 0.0)
     52     , m_userTiming(nullptr)
     53 {
     54 }
     55 
     56 Performance::~Performance()
     57 {
     58 }
     59 
     60 const AtomicString& Performance::interfaceName() const
     61 {
     62     return EventTargetNames::Performance;
     63 }
     64 
     65 ExecutionContext* Performance::executionContext() const
     66 {
     67     if (!frame())
     68         return 0;
     69     return frame()->document();
     70 }
     71 
     72 PassRefPtrWillBeRawPtr<MemoryInfo> Performance::memory() const
     73 {
     74     return MemoryInfo::create();
     75 }
     76 
     77 PerformanceNavigation* Performance::navigation() const
     78 {
     79     if (!m_navigation)
     80         m_navigation = PerformanceNavigation::create(m_frame);
     81 
     82     return m_navigation.get();
     83 }
     84 
     85 PerformanceTiming* Performance::timing() const
     86 {
     87     if (!m_timing)
     88         m_timing = PerformanceTiming::create(m_frame);
     89 
     90     return m_timing.get();
     91 }
     92 
     93 PerformanceEntryVector Performance::getEntries() const
     94 {
     95     PerformanceEntryVector entries;
     96 
     97     entries.appendVector(m_resourceTimingBuffer);
     98 
     99     if (m_userTiming) {
    100         entries.appendVector(m_userTiming->getMarks());
    101         entries.appendVector(m_userTiming->getMeasures());
    102     }
    103 
    104     std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompareLessThan);
    105     return entries;
    106 }
    107 
    108 PerformanceEntryVector Performance::getEntriesByType(const String& entryType)
    109 {
    110     PerformanceEntryVector entries;
    111 
    112     if (equalIgnoringCase(entryType, "resource"))
    113         for (PerformanceEntryVector::const_iterator resource = m_resourceTimingBuffer.begin(); resource != m_resourceTimingBuffer.end(); ++resource)
    114             entries.append(*resource);
    115 
    116     if (m_userTiming) {
    117         if (equalIgnoringCase(entryType, "mark"))
    118             entries.appendVector(m_userTiming->getMarks());
    119         else if (equalIgnoringCase(entryType, "measure"))
    120             entries.appendVector(m_userTiming->getMeasures());
    121     }
    122 
    123     std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompareLessThan);
    124     return entries;
    125 }
    126 
    127 PerformanceEntryVector Performance::getEntriesByName(const String& name, const String& entryType)
    128 {
    129     PerformanceEntryVector entries;
    130 
    131     if (entryType.isNull() || equalIgnoringCase(entryType, "resource"))
    132         for (PerformanceEntryVector::const_iterator resource = m_resourceTimingBuffer.begin(); resource != m_resourceTimingBuffer.end(); ++resource)
    133             if ((*resource)->name() == name)
    134                 entries.append(*resource);
    135 
    136     if (m_userTiming) {
    137         if (entryType.isNull() || equalIgnoringCase(entryType, "mark"))
    138             entries.appendVector(m_userTiming->getMarks(name));
    139         if (entryType.isNull() || equalIgnoringCase(entryType, "measure"))
    140             entries.appendVector(m_userTiming->getMeasures(name));
    141     }
    142 
    143     std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompareLessThan);
    144     return entries;
    145 }
    146 
    147 void Performance::webkitClearResourceTimings()
    148 {
    149     m_resourceTimingBuffer.clear();
    150 }
    151 
    152 void Performance::webkitSetResourceTimingBufferSize(unsigned size)
    153 {
    154     m_resourceTimingBufferSize = size;
    155     if (isResourceTimingBufferFull())
    156         dispatchEvent(Event::create(EventTypeNames::webkitresourcetimingbufferfull));
    157 }
    158 
    159 static bool passesTimingAllowCheck(const ResourceResponse& response, Document* requestingDocument, const AtomicString& originalTimingAllowOrigin)
    160 {
    161     AtomicallyInitializedStatic(AtomicString&, timingAllowOrigin = *new AtomicString("timing-allow-origin"));
    162 
    163     RefPtr<SecurityOrigin> resourceOrigin = SecurityOrigin::create(response.url());
    164     if (resourceOrigin->isSameSchemeHostPort(requestingDocument->securityOrigin()))
    165         return true;
    166 
    167     const AtomicString& timingAllowOriginString = originalTimingAllowOrigin.isEmpty() ? response.httpHeaderField(timingAllowOrigin) : originalTimingAllowOrigin;
    168     if (timingAllowOriginString.isEmpty() || equalIgnoringCase(timingAllowOriginString, "null"))
    169         return false;
    170 
    171     if (timingAllowOriginString == starAtom)
    172         return true;
    173 
    174     const String& securityOrigin = requestingDocument->securityOrigin()->toString();
    175     Vector<String> timingAllowOrigins;
    176     timingAllowOriginString.string().split(' ', timingAllowOrigins);
    177     for (size_t i = 0; i < timingAllowOrigins.size(); ++i) {
    178         if (timingAllowOrigins[i] == securityOrigin)
    179             return true;
    180     }
    181 
    182     return false;
    183 }
    184 
    185 static bool allowsTimingRedirect(const Vector<ResourceResponse>& redirectChain, const ResourceResponse& finalResponse, Document* initiatorDocument)
    186 {
    187     if (!passesTimingAllowCheck(finalResponse, initiatorDocument, emptyAtom))
    188         return false;
    189 
    190     for (size_t i = 0; i < redirectChain.size(); i++) {
    191         if (!passesTimingAllowCheck(redirectChain[i], initiatorDocument, emptyAtom))
    192             return false;
    193     }
    194 
    195     return true;
    196 }
    197 
    198 void Performance::addResourceTiming(const ResourceTimingInfo& info, Document* initiatorDocument)
    199 {
    200     if (isResourceTimingBufferFull())
    201         return;
    202 
    203     const ResourceResponse& finalResponse = info.finalResponse();
    204     bool allowTimingDetails = passesTimingAllowCheck(finalResponse, initiatorDocument, info.originalTimingAllowOrigin());
    205     double startTime = info.initialTime();
    206 
    207     if (info.redirectChain().isEmpty()) {
    208         RefPtrWillBeRawPtr<PerformanceEntry> entry = PerformanceResourceTiming::create(info, initiatorDocument, startTime, allowTimingDetails);
    209         addResourceTimingBuffer(entry);
    210         return;
    211     }
    212 
    213     const Vector<ResourceResponse>& redirectChain = info.redirectChain();
    214     bool allowRedirectDetails = allowsTimingRedirect(redirectChain, finalResponse, initiatorDocument);
    215 
    216     if (!allowRedirectDetails) {
    217         ResourceLoadTiming* finalTiming = finalResponse.resourceLoadTiming();
    218         ASSERT(finalTiming);
    219         if (finalTiming)
    220             startTime = finalTiming->requestTime;
    221     }
    222 
    223     ResourceLoadTiming* lastRedirectTiming = redirectChain.last().resourceLoadTiming();
    224     ASSERT(lastRedirectTiming);
    225     double lastRedirectEndTime = lastRedirectTiming->receiveHeadersEnd;
    226 
    227     RefPtrWillBeRawPtr<PerformanceEntry> entry = PerformanceResourceTiming::create(info, initiatorDocument, startTime, lastRedirectEndTime, allowTimingDetails, allowRedirectDetails);
    228     addResourceTimingBuffer(entry);
    229 }
    230 
    231 void Performance::addResourceTimingBuffer(PassRefPtrWillBeRawPtr<PerformanceEntry> entry)
    232 {
    233     m_resourceTimingBuffer.append(entry);
    234 
    235     if (isResourceTimingBufferFull())
    236         dispatchEvent(Event::create(EventTypeNames::webkitresourcetimingbufferfull));
    237 }
    238 
    239 bool Performance::isResourceTimingBufferFull()
    240 {
    241     return m_resourceTimingBuffer.size() >= m_resourceTimingBufferSize;
    242 }
    243 
    244 void Performance::mark(const String& markName, ExceptionState& exceptionState)
    245 {
    246     if (!m_userTiming)
    247         m_userTiming = UserTiming::create(this);
    248     m_userTiming->mark(markName, exceptionState);
    249 }
    250 
    251 void Performance::clearMarks(const String& markName)
    252 {
    253     if (!m_userTiming)
    254         m_userTiming = UserTiming::create(this);
    255     m_userTiming->clearMarks(markName);
    256 }
    257 
    258 void Performance::measure(const String& measureName, const String& startMark, const String& endMark, ExceptionState& exceptionState)
    259 {
    260     if (!m_userTiming)
    261         m_userTiming = UserTiming::create(this);
    262     m_userTiming->measure(measureName, startMark, endMark, exceptionState);
    263 }
    264 
    265 void Performance::clearMeasures(const String& measureName)
    266 {
    267     if (!m_userTiming)
    268         m_userTiming = UserTiming::create(this);
    269     m_userTiming->clearMeasures(measureName);
    270 }
    271 
    272 double Performance::now() const
    273 {
    274     return 1000.0 * (monotonicallyIncreasingTime() - m_referenceTime);
    275 }
    276 
    277 void Performance::trace(Visitor* visitor)
    278 {
    279     visitor->trace(m_navigation);
    280     visitor->trace(m_timing);
    281     visitor->trace(m_resourceTimingBuffer);
    282     visitor->trace(m_userTiming);
    283     EventTargetWithInlineData::trace(visitor);
    284     DOMWindowProperty::trace(visitor);
    285 }
    286 
    287 } // namespace blink
    288