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)
37OBJC_CLASS NSDictionary;
38#endif
39
40namespace WebCore {
41
42enum class NetworkLoadPriority : uint8_t {
43 Low,
44 Medium,
45 High,
46 Unknown,
47};
48
49class NetworkLoadMetrics {
50public:
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 requestHeaders;
178
179 uint32_t requestHeaderBytesSent;
180 uint32_t responseHeaderBytesReceived;
181 uint64_t requestBodyBytesSent;
182 uint64_t responseBodyBytesReceived;
183 uint64_t responseBodyDecodedSize;
184};
185
186#if PLATFORM(COCOA)
187WEBCORE_EXPORT void copyTimingData(NSDictionary *timingData, NetworkLoadMetrics&);
188#endif
189
190#if PLATFORM(COCOA) && !HAVE(TIMINGDATAOPTIONS)
191WEBCORE_EXPORT void setCollectsTimingData();
192#endif
193
194template<class Encoder>
195void 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
220template<class Decoder>
221bool 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.
249namespace WTF {
250namespace Persistence {
251
252template<> 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