6769e1d53f50f8d04ede3d5cd7f258f02137a34d
[WebKit-https.git] / Source / WebCore / page / PerformanceResourceTiming.cpp
1 /*
2  * Copyright (C) 2012 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 "PerformanceResourceTiming.h"
34
35 #if ENABLE(WEB_TIMING)
36
37 #include "Document.h"
38 #include "DocumentLoader.h"
39 #include "HTTPHeaderNames.h"
40 #include "LoadTiming.h"
41 #include "URL.h"
42 #include "ResourceResponse.h"
43 #include "SecurityOrigin.h"
44 #include <wtf/Vector.h>
45
46 namespace WebCore {
47
48 static double monotonicTimeToDocumentMilliseconds(Document* document, double seconds)
49 {
50     ASSERT(seconds >= 0.0);
51     return Performance::reduceTimeResolution(document->loader()->timing().monotonicTimeToZeroBasedDocumentTime(seconds)) * 1000.0;
52 }
53
54 static bool passesTimingAllowCheck(const ResourceResponse& response, Document* requestingDocument)
55 {
56     Ref<SecurityOrigin> resourceOrigin = SecurityOrigin::create(response.url());
57     if (resourceOrigin->isSameSchemeHostPort(requestingDocument->securityOrigin()))
58         return true;
59
60     const String& timingAllowOriginString = response.httpHeaderField(HTTPHeaderName::TimingAllowOrigin);
61     if (timingAllowOriginString.isEmpty() || equalLettersIgnoringASCIICase(timingAllowOriginString, "null"))
62         return false;
63
64     if (timingAllowOriginString == "*")
65         return true;
66
67     const String& securityOrigin = requestingDocument->securityOrigin().toString();
68     Vector<String> timingAllowOrigins;
69     timingAllowOriginString.split(' ', timingAllowOrigins);
70     for (auto& origin : timingAllowOrigins) {
71         if (origin == securityOrigin)
72             return true;
73     }
74
75     return false;
76 }
77
78 PerformanceResourceTiming::PerformanceResourceTiming(const AtomicString& initiatorType, const URL& originalURL, const ResourceResponse& response, LoadTiming loadTiming, Document* requestingDocument)
79     : PerformanceEntry(PerformanceEntry::Type::Resource, originalURL.string(), ASCIILiteral("resource"), monotonicTimeToDocumentMilliseconds(requestingDocument, loadTiming.startTime()), monotonicTimeToDocumentMilliseconds(requestingDocument, loadTiming.responseEnd()))
80     , m_initiatorType(initiatorType)
81     , m_timing(response.networkLoadTiming())
82     , m_loadTiming(loadTiming)
83     , m_shouldReportDetails(passesTimingAllowCheck(response, requestingDocument))
84     , m_requestingDocument(requestingDocument)
85 {
86 }
87
88 PerformanceResourceTiming::~PerformanceResourceTiming()
89 {
90 }
91
92 AtomicString PerformanceResourceTiming::initiatorType() const
93 {
94     return m_initiatorType;
95 }
96
97 double PerformanceResourceTiming::workerStart() const
98 {
99     return 0.0;
100 }
101
102 double PerformanceResourceTiming::redirectStart() const
103 {
104     if (!m_shouldReportDetails)
105         return 0.0;
106
107     return monotonicTimeToDocumentMilliseconds(m_requestingDocument.get(), m_loadTiming.redirectStart());
108 }
109
110 double PerformanceResourceTiming::redirectEnd() const
111 {
112     if (!m_shouldReportDetails)
113         return 0.0;
114
115     return monotonicTimeToDocumentMilliseconds(m_requestingDocument.get(), m_loadTiming.redirectEnd());
116 }
117
118 double PerformanceResourceTiming::fetchStart() const
119 {
120     return monotonicTimeToDocumentMilliseconds(m_requestingDocument.get(), m_loadTiming.fetchStart());
121 }
122
123 double PerformanceResourceTiming::domainLookupStart() const
124 {
125     if (!m_shouldReportDetails)
126         return 0.0;
127
128     if (m_timing.domainLookupStart <= 0)
129         return fetchStart();
130
131     return resourceTimeToDocumentMilliseconds(m_timing.domainLookupStart);
132 }
133
134 double PerformanceResourceTiming::domainLookupEnd() const
135 {
136     if (!m_shouldReportDetails)
137         return 0.0;
138
139     if (m_timing.domainLookupEnd <= 0)
140         return domainLookupStart();
141
142     return resourceTimeToDocumentMilliseconds(m_timing.domainLookupEnd);
143 }
144
145 double PerformanceResourceTiming::connectStart() const
146 {
147     if (!m_shouldReportDetails)
148         return 0.0;
149
150     // connectStart will be -1 when a network request is not made.
151     if (m_timing.connectStart <= 0)
152         return domainLookupEnd();
153
154     // connectStart includes any DNS time, so we may need to trim that off.
155     double connectStart = m_timing.connectStart;
156     if (m_timing.domainLookupEnd >= 0)
157         connectStart = m_timing.domainLookupEnd;
158
159     return resourceTimeToDocumentMilliseconds(connectStart);
160 }
161
162 double PerformanceResourceTiming::connectEnd() const
163 {
164     if (!m_shouldReportDetails)
165         return 0.0;
166
167     // connectStart will be -1 when a network request is not made.
168     if (m_timing.connectEnd <= 0)
169         return connectStart();
170
171     return resourceTimeToDocumentMilliseconds(m_timing.connectEnd);
172 }
173
174 double PerformanceResourceTiming::secureConnectionStart() const
175 {
176     if (!m_shouldReportDetails)
177         return 0.0;
178
179     if (m_timing.secureConnectionStart < 0) // Secure connection not negotiated.
180         return 0.0;
181
182     return resourceTimeToDocumentMilliseconds(m_timing.secureConnectionStart);
183 }
184
185 double PerformanceResourceTiming::requestStart() const
186 {
187     if (!m_shouldReportDetails)
188         return 0.0;
189
190     return resourceTimeToDocumentMilliseconds(m_timing.requestStart);
191 }
192
193 double PerformanceResourceTiming::responseStart() const
194 {
195     if (!m_shouldReportDetails)
196         return 0.0;
197
198     return resourceTimeToDocumentMilliseconds(m_timing.responseStart);
199 }
200
201 double PerformanceResourceTiming::responseEnd() const
202 {
203     if (!m_shouldReportDetails)
204         return 0.0;
205
206     return monotonicTimeToDocumentMilliseconds(m_requestingDocument.get(), m_loadTiming.responseEnd());
207 }
208
209 double PerformanceResourceTiming::resourceTimeToDocumentMilliseconds(double deltaMilliseconds) const
210 {
211     if (!deltaMilliseconds)
212         return 0.0;
213
214     double documentStartTime = m_requestingDocument->loader()->timing().monotonicTimeToZeroBasedDocumentTime(m_loadTiming.fetchStart()) * 1000.0;
215     double resourceTimeSeconds = (documentStartTime + deltaMilliseconds) / 1000.0;
216     return 1000.0 * Performance::reduceTimeResolution(resourceTimeSeconds);
217 }
218
219 } // namespace WebCore
220
221 #endif // ENABLE(WEB_TIMING)