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