152a9c762b0dee44a088ccf1ebcb68cbd8097b13
[WebKit-https.git] / Source / WebCore / page / PerformanceResourceTiming.cpp
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  * Copyright (C) 2012 Google Inc. All rights reserved.
4  * Copyright (C) 2012 Intel Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above
13  * copyright notice, this list of conditions and the following disclaimer
14  * in the documentation and/or other materials provided with the
15  * distribution.
16  *     * Neither the name of Google Inc. nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "config.h"
34 #include "PerformanceResourceTiming.h"
35
36 #include "Document.h"
37 #include "DocumentLoader.h"
38 #include "LoadTiming.h"
39 #include "ResourceResponse.h"
40 #include "ResourceTiming.h"
41 #include "URL.h"
42
43 namespace WebCore {
44
45 static double monotonicTimeToDOMHighResTimeStamp(MonotonicTime timeOrigin, MonotonicTime timeStamp)
46 {
47     ASSERT(timeStamp.secondsSinceEpoch().seconds() >= 0);
48     if (!timeStamp || !timeOrigin)
49         return 0;
50
51     Seconds seconds = timeStamp - timeOrigin;
52     return Performance::reduceTimeResolution(seconds).milliseconds();
53 }
54
55 static double entryStartTime(MonotonicTime timeOrigin, const ResourceTiming& resourceTiming)
56 {
57     return monotonicTimeToDOMHighResTimeStamp(timeOrigin, resourceTiming.loadTiming().startTime());
58 }
59
60 static double entryEndTime(MonotonicTime timeOrigin, const ResourceTiming& resourceTiming)
61 {
62     if (resourceTiming.networkLoadMetrics().isComplete()) {
63         Seconds endTime = (resourceTiming.loadTiming().fetchStart() + resourceTiming.networkLoadMetrics().responseEnd) - timeOrigin;
64         return Performance::reduceTimeResolution(endTime).milliseconds();
65     }
66
67     return monotonicTimeToDOMHighResTimeStamp(timeOrigin, resourceTiming.loadTiming().responseEnd());
68 }
69
70 Ref<PerformanceResourceTiming> PerformanceResourceTiming::create(MonotonicTime timeOrigin, ResourceTiming&& resourceTiming)
71 {
72     return adoptRef(*new PerformanceResourceTiming(timeOrigin, WTFMove(resourceTiming)));
73 }
74
75 PerformanceResourceTiming::PerformanceResourceTiming(MonotonicTime timeOrigin, ResourceTiming&& resourceTiming)
76     : PerformanceEntry(PerformanceEntry::Type::Resource, resourceTiming.url().string(), ASCIILiteral("resource"), entryStartTime(timeOrigin, resourceTiming), entryEndTime(timeOrigin, resourceTiming))
77     , m_initiatorType(resourceTiming.initiator())
78     , m_timeOrigin(timeOrigin)
79     , m_loadTiming(resourceTiming.loadTiming())
80     , m_networkLoadMetrics(resourceTiming.networkLoadMetrics())
81     , m_shouldReportDetails(resourceTiming.allowTimingDetails())
82 {
83 }
84
85 PerformanceResourceTiming::~PerformanceResourceTiming() = default;
86
87 String PerformanceResourceTiming::nextHopProtocol() const
88 {
89     return m_networkLoadMetrics.protocol;
90 }
91
92 double PerformanceResourceTiming::workerStart() const
93 {
94     return 0.0;
95 }
96
97 double PerformanceResourceTiming::redirectStart() const
98 {
99     if (!m_shouldReportDetails)
100         return 0.0;
101
102     return monotonicTimeToDOMHighResTimeStamp(m_timeOrigin, m_loadTiming.redirectStart());
103 }
104
105 double PerformanceResourceTiming::redirectEnd() const
106 {
107     if (!m_shouldReportDetails)
108         return 0.0;
109
110     return monotonicTimeToDOMHighResTimeStamp(m_timeOrigin, m_loadTiming.redirectEnd());
111 }
112
113 double PerformanceResourceTiming::fetchStart() const
114 {
115     // fetchStart is a required property.
116     ASSERT(m_loadTiming.fetchStart());
117
118     return monotonicTimeToDOMHighResTimeStamp(m_timeOrigin, m_loadTiming.fetchStart());
119 }
120
121 double PerformanceResourceTiming::domainLookupStart() const
122 {
123     if (!m_shouldReportDetails)
124         return 0.0;
125
126     if (m_networkLoadMetrics.domainLookupStart <= 0_ms)
127         return fetchStart();
128
129     return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.domainLookupStart);
130 }
131
132 double PerformanceResourceTiming::domainLookupEnd() const
133 {
134     if (!m_shouldReportDetails)
135         return 0.0;
136
137     if (m_networkLoadMetrics.domainLookupEnd <= 0_ms)
138         return domainLookupStart();
139
140     return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.domainLookupEnd);
141 }
142
143 double PerformanceResourceTiming::connectStart() const
144 {
145     if (!m_shouldReportDetails)
146         return 0.0;
147
148     if (m_networkLoadMetrics.connectStart <= 0_ms)
149         return domainLookupEnd();
150
151     return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.connectStart);
152 }
153
154 double PerformanceResourceTiming::connectEnd() const
155 {
156     if (!m_shouldReportDetails)
157         return 0.0;
158
159     if (m_networkLoadMetrics.connectEnd <= 0_ms)
160         return connectStart();
161
162     return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.connectEnd);
163 }
164
165 double PerformanceResourceTiming::secureConnectionStart() const
166 {
167     if (!m_shouldReportDetails)
168         return 0.0;
169
170     if (m_networkLoadMetrics.secureConnectionStart <= 0_ms)
171         return 0.0;
172
173     return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.secureConnectionStart);
174 }
175
176 double PerformanceResourceTiming::requestStart() const
177 {
178     if (!m_shouldReportDetails)
179         return 0.0;
180
181     // requestStart is 0 when a network request is not made.
182     if (m_networkLoadMetrics.requestStart <= 0_ms)
183         return connectEnd();
184
185     return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.requestStart);
186 }
187
188 double PerformanceResourceTiming::responseStart() const
189 {
190     if (!m_shouldReportDetails)
191         return 0.0;
192
193     // responseStart is 0 when a network request is not made.
194     if (m_networkLoadMetrics.responseStart <= 0_ms)
195         return requestStart();
196
197     return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.responseStart);
198 }
199
200 double PerformanceResourceTiming::responseEnd() const
201 {
202     // responseEnd is a required property.
203     ASSERT(m_networkLoadMetrics.isComplete() || m_loadTiming.responseEnd());
204
205     if (m_networkLoadMetrics.isComplete()) {
206         // responseEnd is 0 when a network request is not made.
207         // This should mean all other properties are empty.
208         if (m_networkLoadMetrics.responseEnd <= 0_ms) {
209             ASSERT(m_networkLoadMetrics.responseStart <= 0_ms);
210             ASSERT(m_networkLoadMetrics.requestStart <= 0_ms);
211             ASSERT(m_networkLoadMetrics.requestStart <= 0_ms);
212             ASSERT(m_networkLoadMetrics.secureConnectionStart <= 0_ms);
213             ASSERT(m_networkLoadMetrics.connectEnd <= 0_ms);
214             ASSERT(m_networkLoadMetrics.connectStart <= 0_ms);
215             ASSERT(m_networkLoadMetrics.domainLookupEnd <= 0_ms);
216             ASSERT(m_networkLoadMetrics.domainLookupStart <= 0_ms);
217             return fetchStart();
218         }
219
220         return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.responseEnd);
221     }
222
223     return monotonicTimeToDOMHighResTimeStamp(m_timeOrigin, m_loadTiming.responseEnd());
224 }
225
226 double PerformanceResourceTiming::networkLoadTimeToDOMHighResTimeStamp(Seconds delta) const
227 {
228     ASSERT(delta);
229     Seconds final = (m_loadTiming.fetchStart() + delta) - m_timeOrigin;
230     return Performance::reduceTimeResolution(final).milliseconds();
231 }
232
233 } // namespace WebCore