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 "PerformanceServerTiming.h" |
40 | #include "ResourceResponse.h" |
41 | #include "ResourceTiming.h" |
42 | #include <wtf/URL.h> |
43 | |
44 | namespace WebCore { |
45 | |
46 | static double monotonicTimeToDOMHighResTimeStamp(MonotonicTime timeOrigin, MonotonicTime timeStamp) |
47 | { |
48 | ASSERT(timeStamp.secondsSinceEpoch().seconds() >= 0); |
49 | if (!timeStamp || !timeOrigin) |
50 | return 0; |
51 | |
52 | Seconds seconds = timeStamp - timeOrigin; |
53 | return Performance::reduceTimeResolution(seconds).milliseconds(); |
54 | } |
55 | |
56 | static double entryStartTime(MonotonicTime timeOrigin, const ResourceTiming& resourceTiming) |
57 | { |
58 | if (!resourceTiming.allowTimingDetails()) |
59 | return monotonicTimeToDOMHighResTimeStamp(timeOrigin, resourceTiming.loadTiming().fetchStart()); |
60 | |
61 | return monotonicTimeToDOMHighResTimeStamp(timeOrigin, resourceTiming.loadTiming().startTime()); |
62 | } |
63 | |
64 | static double entryEndTime(MonotonicTime timeOrigin, const ResourceTiming& resourceTiming) |
65 | { |
66 | if (!resourceTiming.allowTimingDetails()) |
67 | return entryStartTime(timeOrigin, resourceTiming); |
68 | |
69 | if (resourceTiming.networkLoadMetrics().isComplete()) { |
70 | Seconds endTime = (resourceTiming.loadTiming().fetchStart() + resourceTiming.networkLoadMetrics().responseEnd) - timeOrigin; |
71 | return Performance::reduceTimeResolution(endTime).milliseconds(); |
72 | } |
73 | |
74 | return monotonicTimeToDOMHighResTimeStamp(timeOrigin, resourceTiming.loadTiming().responseEnd()); |
75 | } |
76 | |
77 | Ref<PerformanceResourceTiming> PerformanceResourceTiming::create(MonotonicTime timeOrigin, ResourceTiming&& resourceTiming) |
78 | { |
79 | return adoptRef(*new PerformanceResourceTiming(timeOrigin, WTFMove(resourceTiming))); |
80 | } |
81 | |
82 | PerformanceResourceTiming::PerformanceResourceTiming(MonotonicTime timeOrigin, ResourceTiming&& resourceTiming) |
83 | : PerformanceEntry(PerformanceEntry::Type::Resource, resourceTiming.url().string(), "resource"_s , entryStartTime(timeOrigin, resourceTiming), entryEndTime(timeOrigin, resourceTiming)) |
84 | , m_initiatorType(resourceTiming.initiator()) |
85 | , m_timeOrigin(timeOrigin) |
86 | , m_loadTiming(resourceTiming.loadTiming()) |
87 | , m_networkLoadMetrics(resourceTiming.networkLoadMetrics()) |
88 | , m_shouldReportDetails(resourceTiming.allowTimingDetails()) |
89 | , m_serverTiming(resourceTiming.populateServerTiming()) |
90 | { |
91 | m_networkLoadMetrics.clearNonTimingData(); |
92 | } |
93 | |
94 | PerformanceResourceTiming::~PerformanceResourceTiming() = default; |
95 | |
96 | String PerformanceResourceTiming::nextHopProtocol() const |
97 | { |
98 | return m_networkLoadMetrics.protocol; |
99 | } |
100 | |
101 | double PerformanceResourceTiming::workerStart() const |
102 | { |
103 | // FIXME: <https://webkit.org/b/179377> Implement PerformanceResourceTiming.workerStart in ServiceWorkers |
104 | return 0.0; |
105 | } |
106 | |
107 | double PerformanceResourceTiming::redirectStart() const |
108 | { |
109 | if (!m_shouldReportDetails) |
110 | return 0.0; |
111 | |
112 | return monotonicTimeToDOMHighResTimeStamp(m_timeOrigin, m_loadTiming.redirectStart()); |
113 | } |
114 | |
115 | double PerformanceResourceTiming::redirectEnd() const |
116 | { |
117 | if (!m_shouldReportDetails) |
118 | return 0.0; |
119 | |
120 | return monotonicTimeToDOMHighResTimeStamp(m_timeOrigin, m_loadTiming.redirectEnd()); |
121 | } |
122 | |
123 | double PerformanceResourceTiming::fetchStart() const |
124 | { |
125 | // fetchStart is a required property. |
126 | ASSERT(m_loadTiming.fetchStart()); |
127 | |
128 | return monotonicTimeToDOMHighResTimeStamp(m_timeOrigin, m_loadTiming.fetchStart()); |
129 | } |
130 | |
131 | double PerformanceResourceTiming::domainLookupStart() const |
132 | { |
133 | if (!m_shouldReportDetails) |
134 | return 0.0; |
135 | |
136 | if (m_networkLoadMetrics.domainLookupStart <= 0_ms) |
137 | return fetchStart(); |
138 | |
139 | return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.domainLookupStart); |
140 | } |
141 | |
142 | double PerformanceResourceTiming::domainLookupEnd() const |
143 | { |
144 | if (!m_shouldReportDetails) |
145 | return 0.0; |
146 | |
147 | if (m_networkLoadMetrics.domainLookupEnd <= 0_ms) |
148 | return domainLookupStart(); |
149 | |
150 | return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.domainLookupEnd); |
151 | } |
152 | |
153 | double PerformanceResourceTiming::connectStart() const |
154 | { |
155 | if (!m_shouldReportDetails) |
156 | return 0.0; |
157 | |
158 | if (m_networkLoadMetrics.connectStart <= 0_ms) |
159 | return domainLookupEnd(); |
160 | |
161 | return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.connectStart); |
162 | } |
163 | |
164 | double PerformanceResourceTiming::connectEnd() const |
165 | { |
166 | if (!m_shouldReportDetails) |
167 | return 0.0; |
168 | |
169 | if (m_networkLoadMetrics.connectEnd <= 0_ms) |
170 | return connectStart(); |
171 | |
172 | return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.connectEnd); |
173 | } |
174 | |
175 | double PerformanceResourceTiming::secureConnectionStart() const |
176 | { |
177 | if (!m_shouldReportDetails) |
178 | return 0.0; |
179 | |
180 | if (m_networkLoadMetrics.secureConnectionStart <= 0_ms) |
181 | return 0.0; |
182 | |
183 | return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.secureConnectionStart); |
184 | } |
185 | |
186 | double PerformanceResourceTiming::requestStart() const |
187 | { |
188 | if (!m_shouldReportDetails) |
189 | return 0.0; |
190 | |
191 | // requestStart is 0 when a network request is not made. |
192 | if (m_networkLoadMetrics.requestStart <= 0_ms) |
193 | return connectEnd(); |
194 | |
195 | return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.requestStart); |
196 | } |
197 | |
198 | double PerformanceResourceTiming::responseStart() const |
199 | { |
200 | if (!m_shouldReportDetails) |
201 | return 0.0; |
202 | |
203 | // responseStart is 0 when a network request is not made. |
204 | if (m_networkLoadMetrics.responseStart <= 0_ms) |
205 | return requestStart(); |
206 | |
207 | return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.responseStart); |
208 | } |
209 | |
210 | double PerformanceResourceTiming::responseEnd() const |
211 | { |
212 | // responseEnd is a required property. |
213 | ASSERT(m_networkLoadMetrics.isComplete() || m_loadTiming.responseEnd()); |
214 | |
215 | if (m_networkLoadMetrics.isComplete()) { |
216 | // responseEnd is 0 when a network request is not made. |
217 | // This should mean all other properties are empty. |
218 | if (m_networkLoadMetrics.responseEnd <= 0_ms) { |
219 | ASSERT(m_networkLoadMetrics.responseStart <= 0_ms); |
220 | ASSERT(m_networkLoadMetrics.requestStart <= 0_ms); |
221 | ASSERT(m_networkLoadMetrics.requestStart <= 0_ms); |
222 | ASSERT(m_networkLoadMetrics.secureConnectionStart <= 0_ms); |
223 | ASSERT(m_networkLoadMetrics.connectEnd <= 0_ms); |
224 | ASSERT(m_networkLoadMetrics.connectStart <= 0_ms); |
225 | ASSERT(m_networkLoadMetrics.domainLookupEnd <= 0_ms); |
226 | ASSERT(m_networkLoadMetrics.domainLookupStart <= 0_ms); |
227 | return fetchStart(); |
228 | } |
229 | |
230 | return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.responseEnd); |
231 | } |
232 | |
233 | return monotonicTimeToDOMHighResTimeStamp(m_timeOrigin, m_loadTiming.responseEnd()); |
234 | } |
235 | |
236 | double PerformanceResourceTiming::networkLoadTimeToDOMHighResTimeStamp(Seconds delta) const |
237 | { |
238 | ASSERT(delta); |
239 | Seconds final = (m_loadTiming.fetchStart() + delta) - m_timeOrigin; |
240 | return Performance::reduceTimeResolution(final).milliseconds(); |
241 | } |
242 | |
243 | } // namespace WebCore |
244 | |