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