1 | /* |
2 | * Copyright (C) 2010 Google, Inc. All Rights Reserved. |
3 | * Copyright (C) 2014-2017 Apple, 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 |
7 | * are met: |
8 | * 1. Redistributions of source code must retain the above copyright |
9 | * notice, this list of conditions and the following disclaimer. |
10 | * 2. Redistributions in binary form must reproduce the above copyright |
11 | * notice, this list of conditions and the following disclaimer in the |
12 | * documentation and/or other materials provided with the distribution. |
13 | * |
14 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
15 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
17 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
18 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
19 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
21 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
22 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 | */ |
26 | |
27 | #pragma once |
28 | |
29 | #include "HTTPHeaderMap.h" |
30 | #include <wtf/Optional.h> |
31 | #include <wtf/Seconds.h> |
32 | #include <wtf/persistence/PersistentDecoder.h> |
33 | #include <wtf/persistence/PersistentEncoder.h> |
34 | #include <wtf/text/WTFString.h> |
35 | |
36 | #if PLATFORM(COCOA) |
37 | OBJC_CLASS NSDictionary; |
38 | #endif |
39 | |
40 | namespace WebCore { |
41 | |
42 | enum class NetworkLoadPriority : uint8_t { |
43 | Low, |
44 | Medium, |
45 | High, |
46 | Unknown, |
47 | }; |
48 | |
49 | class NetworkLoadMetrics { |
50 | public: |
51 | NetworkLoadMetrics() |
52 | { |
53 | reset(); |
54 | } |
55 | |
56 | NetworkLoadMetrics isolatedCopy() const |
57 | { |
58 | NetworkLoadMetrics copy; |
59 | |
60 | copy.domainLookupStart = domainLookupStart; |
61 | copy.domainLookupEnd = domainLookupEnd; |
62 | copy.connectStart = connectStart; |
63 | copy.secureConnectionStart = secureConnectionStart; |
64 | copy.connectEnd = connectEnd; |
65 | copy.requestStart = requestStart; |
66 | copy.responseStart = responseStart; |
67 | copy.responseEnd = responseEnd; |
68 | copy.complete = complete; |
69 | copy.protocol = protocol.isolatedCopy(); |
70 | |
71 | copy.remoteAddress = remoteAddress.isolatedCopy(); |
72 | copy.connectionIdentifier = connectionIdentifier.isolatedCopy(); |
73 | copy.priority = priority; |
74 | copy.tlsProtocol = tlsProtocol.isolatedCopy(); |
75 | copy.tlsCipher = tlsCipher.isolatedCopy(); |
76 | copy.requestHeaders = requestHeaders.isolatedCopy(); |
77 | |
78 | copy.requestHeaderBytesSent = requestHeaderBytesSent; |
79 | copy.requestBodyBytesSent = requestBodyBytesSent; |
80 | copy.responseHeaderBytesReceived = responseHeaderBytesReceived; |
81 | copy.responseBodyBytesReceived = responseBodyBytesReceived; |
82 | copy.responseBodyDecodedSize = responseBodyDecodedSize; |
83 | |
84 | return copy; |
85 | } |
86 | |
87 | void reset() |
88 | { |
89 | domainLookupStart = Seconds(-1); |
90 | domainLookupEnd = Seconds(-1); |
91 | connectStart = Seconds(-1); |
92 | secureConnectionStart = Seconds(-1); |
93 | connectEnd = Seconds(-1); |
94 | requestStart = Seconds(0); |
95 | responseStart = Seconds(0); |
96 | responseEnd = Seconds(0); |
97 | complete = false; |
98 | protocol = String(); |
99 | clearNonTimingData(); |
100 | } |
101 | |
102 | void clearNonTimingData() |
103 | { |
104 | remoteAddress = String(); |
105 | connectionIdentifier = String(); |
106 | priority = NetworkLoadPriority::Unknown; |
107 | tlsProtocol = String(); |
108 | tlsCipher = String(); |
109 | requestHeaders.clear(); |
110 | requestHeaderBytesSent = std::numeric_limits<uint32_t>::max(); |
111 | requestBodyBytesSent = std::numeric_limits<uint64_t>::max(); |
112 | responseHeaderBytesReceived = std::numeric_limits<uint32_t>::max(); |
113 | responseBodyBytesReceived = std::numeric_limits<uint64_t>::max(); |
114 | responseBodyDecodedSize = std::numeric_limits<uint64_t>::max(); |
115 | } |
116 | |
117 | bool operator==(const NetworkLoadMetrics& other) const |
118 | { |
119 | return domainLookupStart == other.domainLookupStart |
120 | && domainLookupEnd == other.domainLookupEnd |
121 | && connectStart == other.connectStart |
122 | && secureConnectionStart == other.secureConnectionStart |
123 | && connectEnd == other.connectEnd |
124 | && requestStart == other.requestStart |
125 | && responseStart == other.responseStart |
126 | && responseEnd == other.responseEnd |
127 | && complete == other.complete |
128 | && protocol == other.protocol |
129 | && remoteAddress == other.remoteAddress |
130 | && connectionIdentifier == other.connectionIdentifier |
131 | && priority == other.priority |
132 | && tlsProtocol == other.tlsProtocol |
133 | && tlsCipher == other.tlsCipher |
134 | && requestHeaders == other.requestHeaders |
135 | && requestHeaderBytesSent == other.requestHeaderBytesSent |
136 | && requestBodyBytesSent == other.requestBodyBytesSent |
137 | && responseHeaderBytesReceived == other.responseHeaderBytesReceived |
138 | && responseBodyBytesReceived == other.responseBodyBytesReceived |
139 | && responseBodyDecodedSize == other.responseBodyDecodedSize; |
140 | } |
141 | |
142 | bool operator!=(const NetworkLoadMetrics& other) const |
143 | { |
144 | return !(*this == other); |
145 | } |
146 | |
147 | bool isComplete() const { return complete; } |
148 | void markComplete() { complete = true; } |
149 | |
150 | template<class Encoder> void encode(Encoder&) const; |
151 | template<class Decoder> static bool decode(Decoder&, NetworkLoadMetrics&); |
152 | |
153 | // These should be treated as deltas to LoadTiming's fetchStart. |
154 | // They should be in ascending order as listed here. |
155 | Seconds domainLookupStart; // -1 if no DNS. |
156 | Seconds domainLookupEnd; // -1 if no DNS. |
157 | Seconds connectStart; // -1 if reused connection. |
158 | Seconds secureConnectionStart; // -1 if no secure connection. |
159 | Seconds connectEnd; // -1 if reused connection. |
160 | Seconds requestStart; |
161 | Seconds responseStart; |
162 | Seconds responseEnd; |
163 | |
164 | // ALPN Protocol ID: https://w3c.github.io/resource-timing/#bib-RFC7301 |
165 | String protocol; |
166 | |
167 | String remoteAddress; |
168 | String connectionIdentifier; |
169 | NetworkLoadPriority priority; |
170 | |
171 | String tlsProtocol; |
172 | String tlsCipher; |
173 | |
174 | // Whether or not all of the properties (0 or otherwise) have been set. |
175 | bool complete { false }; |
176 | |
177 | HTTPHeaderMap ; |
178 | |
179 | uint32_t ; |
180 | uint32_t ; |
181 | uint64_t requestBodyBytesSent; |
182 | uint64_t responseBodyBytesReceived; |
183 | uint64_t responseBodyDecodedSize; |
184 | }; |
185 | |
186 | #if PLATFORM(COCOA) |
187 | WEBCORE_EXPORT void copyTimingData(NSDictionary *timingData, NetworkLoadMetrics&); |
188 | #endif |
189 | |
190 | #if PLATFORM(COCOA) && !HAVE(TIMINGDATAOPTIONS) |
191 | WEBCORE_EXPORT void setCollectsTimingData(); |
192 | #endif |
193 | |
194 | template<class Encoder> |
195 | void NetworkLoadMetrics::encode(Encoder& encoder) const |
196 | { |
197 | encoder << domainLookupStart; |
198 | encoder << domainLookupEnd; |
199 | encoder << connectStart; |
200 | encoder << secureConnectionStart; |
201 | encoder << connectEnd; |
202 | encoder << requestStart; |
203 | encoder << responseStart; |
204 | encoder << responseEnd; |
205 | encoder << complete; |
206 | encoder << protocol; |
207 | encoder << remoteAddress; |
208 | encoder << connectionIdentifier; |
209 | encoder << priority; |
210 | encoder << tlsProtocol; |
211 | encoder << tlsCipher; |
212 | encoder << requestHeaders; |
213 | encoder << requestHeaderBytesSent; |
214 | encoder << requestBodyBytesSent; |
215 | encoder << responseHeaderBytesReceived; |
216 | encoder << responseBodyBytesReceived; |
217 | encoder << responseBodyDecodedSize; |
218 | } |
219 | |
220 | template<class Decoder> |
221 | bool NetworkLoadMetrics::decode(Decoder& decoder, NetworkLoadMetrics& metrics) |
222 | { |
223 | return decoder.decode(metrics.domainLookupStart) |
224 | && decoder.decode(metrics.domainLookupEnd) |
225 | && decoder.decode(metrics.connectStart) |
226 | && decoder.decode(metrics.secureConnectionStart) |
227 | && decoder.decode(metrics.connectEnd) |
228 | && decoder.decode(metrics.requestStart) |
229 | && decoder.decode(metrics.responseStart) |
230 | && decoder.decode(metrics.responseEnd) |
231 | && decoder.decode(metrics.complete) |
232 | && decoder.decode(metrics.protocol) |
233 | && decoder.decode(metrics.remoteAddress) |
234 | && decoder.decode(metrics.connectionIdentifier) |
235 | && decoder.decode(metrics.priority) |
236 | && decoder.decode(metrics.tlsProtocol) |
237 | && decoder.decode(metrics.tlsCipher) |
238 | && decoder.decode(metrics.requestHeaders) |
239 | && decoder.decode(metrics.requestHeaderBytesSent) |
240 | && decoder.decode(metrics.requestBodyBytesSent) |
241 | && decoder.decode(metrics.responseHeaderBytesReceived) |
242 | && decoder.decode(metrics.responseBodyBytesReceived) |
243 | && decoder.decode(metrics.responseBodyDecodedSize); |
244 | } |
245 | |
246 | } // namespace WebCore |
247 | |
248 | // NetworkLoadMetrics should not be stored by the WTF::Persistence::Decoder. |
249 | namespace WTF { |
250 | namespace Persistence { |
251 | |
252 | template<> struct Coder<Optional<WebCore::NetworkLoadPriority>> { |
253 | static NO_RETURN_DUE_TO_ASSERT void encode(Encoder&, const Optional<WebCore::NetworkLoadPriority>&) |
254 | { |
255 | ASSERT_NOT_REACHED(); |
256 | } |
257 | |
258 | static bool decode(Decoder&, Optional<WebCore::NetworkLoadPriority>&) |
259 | { |
260 | ASSERT_NOT_REACHED(); |
261 | return false; |
262 | } |
263 | }; |
264 | |
265 | }} // namespace WTF::Persistence |
266 | |