Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / timing / Performance.cpp
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