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/loader/DocumentLoader.h"
     37 #include "core/timing/ResourceTimingInfo.h"
     38 #include "core/timing/PerformanceResourceTiming.h"
     39 #include "core/timing/PerformanceUserTiming.h"
     40 #include "platform/weborigin/SecurityOrigin.h"
     41 #include "wtf/CurrentTime.h"
     42 
     43 #include "core/frame/Frame.h"
     44 
     45 namespace WebCore {
     46 
     47 static const size_t defaultResourceTimingBufferSize = 150;
     48 
     49 Performance::Performance(Frame* frame)
     50     : DOMWindowProperty(frame)
     51     , m_resourceTimingBufferSize(defaultResourceTimingBufferSize)
     52     , m_referenceTime(frame->document()->loader()->timing()->referenceMonotonicTime())
     53     , m_userTiming(0)
     54 {
     55     ASSERT(m_referenceTime);
     56     ScriptWrappable::init(this);
     57 }
     58 
     59 Performance::~Performance()
     60 {
     61 }
     62 
     63 const AtomicString& Performance::interfaceName() const
     64 {
     65     return EventTargetNames::Performance;
     66 }
     67 
     68 ExecutionContext* Performance::executionContext() const
     69 {
     70     if (!frame())
     71         return 0;
     72     return frame()->document();
     73 }
     74 
     75 PassRefPtr<MemoryInfo> Performance::memory() const
     76 {
     77     return MemoryInfo::create(m_frame);
     78 }
     79 
     80 PerformanceNavigation* Performance::navigation() const
     81 {
     82     if (!m_navigation)
     83         m_navigation = PerformanceNavigation::create(m_frame);
     84 
     85     return m_navigation.get();
     86 }
     87 
     88 PerformanceTiming* Performance::timing() const
     89 {
     90     if (!m_timing)
     91         m_timing = PerformanceTiming::create(m_frame);
     92 
     93     return m_timing.get();
     94 }
     95 
     96 Vector<RefPtr<PerformanceEntry> > Performance::getEntries() const
     97 {
     98     Vector<RefPtr<PerformanceEntry> > entries;
     99 
    100     entries.append(m_resourceTimingBuffer);
    101 
    102     if (m_userTiming) {
    103         entries.append(m_userTiming->getMarks());
    104         entries.append(m_userTiming->getMeasures());
    105     }
    106 
    107     std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompareLessThan);
    108     return entries;
    109 }
    110 
    111 Vector<RefPtr<PerformanceEntry> > Performance::getEntriesByType(const String& entryType)
    112 {
    113     Vector<RefPtr<PerformanceEntry> > entries;
    114 
    115     if (equalIgnoringCase(entryType, "resource"))
    116         for (Vector<RefPtr<PerformanceEntry> >::const_iterator resource = m_resourceTimingBuffer.begin(); resource != m_resourceTimingBuffer.end(); ++resource)
    117             entries.append(*resource);
    118 
    119     if (m_userTiming) {
    120         if (equalIgnoringCase(entryType, "mark"))
    121             entries.append(m_userTiming->getMarks());
    122         else if (equalIgnoringCase(entryType, "measure"))
    123             entries.append(m_userTiming->getMeasures());
    124     }
    125 
    126     std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompareLessThan);
    127     return entries;
    128 }
    129 
    130 Vector<RefPtr<PerformanceEntry> > Performance::getEntriesByName(const String& name, const String& entryType)
    131 {
    132     Vector<RefPtr<PerformanceEntry> > entries;
    133 
    134     if (entryType.isNull() || equalIgnoringCase(entryType, "resource"))
    135         for (Vector<RefPtr<PerformanceEntry> >::const_iterator resource = m_resourceTimingBuffer.begin(); resource != m_resourceTimingBuffer.end(); ++resource)
    136             if ((*resource)->name() == name)
    137                 entries.append(*resource);
    138 
    139     if (m_userTiming) {
    140         if (entryType.isNull() || equalIgnoringCase(entryType, "mark"))
    141             entries.append(m_userTiming->getMarks(name));
    142         if (entryType.isNull() || equalIgnoringCase(entryType, "measure"))
    143             entries.append(m_userTiming->getMeasures(name));
    144     }
    145 
    146     std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompareLessThan);
    147     return entries;
    148 }
    149 
    150 void Performance::webkitClearResourceTimings()
    151 {
    152     m_resourceTimingBuffer.clear();
    153 }
    154 
    155 void Performance::webkitSetResourceTimingBufferSize(unsigned size)
    156 {
    157     m_resourceTimingBufferSize = size;
    158     if (isResourceTimingBufferFull())
    159         dispatchEvent(Event::create(EventTypeNames::webkitresourcetimingbufferfull));
    160 }
    161 
    162 static bool passesTimingAllowCheck(const ResourceResponse& response, Document* requestingDocument)
    163 {
    164     AtomicallyInitializedStatic(AtomicString&, timingAllowOrigin = *new AtomicString("timing-allow-origin"));
    165 
    166     RefPtr<SecurityOrigin> resourceOrigin = SecurityOrigin::create(response.url());
    167     if (resourceOrigin->isSameSchemeHostPort(requestingDocument->securityOrigin()))
    168         return true;
    169 
    170     const AtomicString& timingAllowOriginString = response.httpHeaderField(timingAllowOrigin);
    171     if (timingAllowOriginString.isEmpty() || equalIgnoringCase(timingAllowOriginString, "null"))
    172         return false;
    173 
    174     if (timingAllowOriginString == starAtom)
    175         return true;
    176 
    177     const String& securityOrigin = requestingDocument->securityOrigin()->toString();
    178     Vector<String> timingAllowOrigins;
    179     timingAllowOriginString.string().split(" ", timingAllowOrigins);
    180     for (size_t i = 0; i < timingAllowOrigins.size(); ++i) {
    181         if (timingAllowOrigins[i] == securityOrigin)
    182             return true;
    183     }
    184 
    185     return false;
    186 }
    187 
    188 static bool allowsTimingRedirect(const Vector<ResourceResponse>& redirectChain, const ResourceResponse& finalResponse, Document* initiatorDocument)
    189 {
    190     if (!passesTimingAllowCheck(finalResponse, initiatorDocument))
    191         return false;
    192 
    193     for (size_t i = 0; i < redirectChain.size(); i++) {
    194         if (!passesTimingAllowCheck(redirectChain[i], initiatorDocument))
    195             return false;
    196     }
    197 
    198     return true;
    199 }
    200 
    201 void Performance::addResourceTiming(const ResourceTimingInfo& info, Document* initiatorDocument)
    202 {
    203     if (isResourceTimingBufferFull())
    204         return;
    205 
    206     const ResourceResponse& finalResponse = info.finalResponse();
    207     bool allowTimingDetails = passesTimingAllowCheck(finalResponse, initiatorDocument);
    208     double startTime = info.initialTime();
    209 
    210     if (info.redirectChain().isEmpty()) {
    211         RefPtr<PerformanceEntry> entry = PerformanceResourceTiming::create(info, initiatorDocument, startTime, allowTimingDetails);
    212         addResourceTimingBuffer(entry);
    213         return;
    214     }
    215 
    216     const Vector<ResourceResponse>& redirectChain = info.redirectChain();
    217     bool allowRedirectDetails = allowsTimingRedirect(redirectChain, finalResponse, initiatorDocument);
    218 
    219     if (!allowRedirectDetails) {
    220         ResourceLoadTiming* finalTiming = finalResponse.resourceLoadTiming();
    221         ASSERT(finalTiming);
    222         if (finalTiming)
    223             startTime = finalTiming->requestTime;
    224     }
    225 
    226     ResourceLoadTiming* lastRedirectTiming = redirectChain.last().resourceLoadTiming();
    227     ASSERT(lastRedirectTiming);
    228     double lastRedirectEndTime = lastRedirectTiming->receiveHeadersEnd;
    229 
    230     RefPtr<PerformanceEntry> entry = PerformanceResourceTiming::create(info, initiatorDocument, startTime, lastRedirectEndTime, allowTimingDetails, allowRedirectDetails);
    231     addResourceTimingBuffer(entry);
    232 }
    233 
    234 void Performance::addResourceTimingBuffer(PassRefPtr<PerformanceEntry> entry)
    235 {
    236     m_resourceTimingBuffer.append(entry);
    237 
    238     if (isResourceTimingBufferFull())
    239         dispatchEvent(Event::create(EventTypeNames::webkitresourcetimingbufferfull));
    240 }
    241 
    242 bool Performance::isResourceTimingBufferFull()
    243 {
    244     return m_resourceTimingBuffer.size() >= m_resourceTimingBufferSize;
    245 }
    246 
    247 void Performance::mark(const String& markName, ExceptionState& exceptionState)
    248 {
    249     if (!m_userTiming)
    250         m_userTiming = UserTiming::create(this);
    251     m_userTiming->mark(markName, exceptionState);
    252 }
    253 
    254 void Performance::clearMarks(const String& markName)
    255 {
    256     if (!m_userTiming)
    257         m_userTiming = UserTiming::create(this);
    258     m_userTiming->clearMarks(markName);
    259 }
    260 
    261 void Performance::measure(const String& measureName, const String& startMark, const String& endMark, ExceptionState& exceptionState)
    262 {
    263     if (!m_userTiming)
    264         m_userTiming = UserTiming::create(this);
    265     m_userTiming->measure(measureName, startMark, endMark, exceptionState);
    266 }
    267 
    268 void Performance::clearMeasures(const String& measureName)
    269 {
    270     if (!m_userTiming)
    271         m_userTiming = UserTiming::create(this);
    272     m_userTiming->clearMeasures(measureName);
    273 }
    274 
    275 double Performance::now() const
    276 {
    277     return 1000.0 * (monotonicallyIncreasingTime() - m_referenceTime);
    278 }
    279 
    280 } // namespace WebCore
    281