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