c6363b450753f93d21e6ef58f7e2af2a43ee347d
[WebKit-https.git] / Source / WebCore / page / PerformanceResourceTiming.cpp
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  * Copyright (C) 2012 Intel 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 are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "PerformanceResourceTiming.h"
34
35 #if ENABLE(WEB_TIMING)
36
37 #include "Document.h"
38 #include "DocumentLoader.h"
39 #include "HTTPHeaderNames.h"
40 #include "LoadTiming.h"
41 #include "URL.h"
42 #include "ResourceRequest.h"
43 #include "ResourceResponse.h"
44 #include "SecurityOrigin.h"
45 #include <wtf/Vector.h>
46
47 namespace WebCore {
48
49 static double monotonicTimeToDocumentMilliseconds(Document* document, double seconds)
50 {
51     ASSERT(seconds >= 0.0);
52     return Performance::reduceTimeResolution(document->loader()->timing().monotonicTimeToZeroBasedDocumentTime(seconds)) * 1000.0;
53 }
54
55 static bool passesTimingAllowCheck(const ResourceResponse& response, Document* requestingDocument)
56 {
57     RefPtr<SecurityOrigin> resourceOrigin = SecurityOrigin::create(response.url());
58     if (resourceOrigin->isSameSchemeHostPort(requestingDocument->securityOrigin()))
59         return true;
60
61     const String& timingAllowOriginString = response.httpHeaderField(HTTPHeaderName::TimingAllowOrigin);
62     if (timingAllowOriginString.isEmpty() || equalLettersIgnoringASCIICase(timingAllowOriginString, "null"))
63         return false;
64
65     if (timingAllowOriginString == "*")
66         return true;
67
68     const String& securityOrigin = requestingDocument->securityOrigin()->toString();
69     Vector<String> timingAllowOrigins;
70     timingAllowOriginString.split(' ', timingAllowOrigins);
71     for (auto& origin : timingAllowOrigins) {
72         if (origin == securityOrigin)
73             return true;
74     }
75
76     return false;
77 }
78
79 PerformanceResourceTiming::PerformanceResourceTiming(const AtomicString& initiatorType, const ResourceRequest& request, const ResourceResponse& response, double initiationTime, double finishTime, Document* requestingDocument)
80     : PerformanceEntry(request.url().string(), "resource", monotonicTimeToDocumentMilliseconds(requestingDocument, initiationTime), monotonicTimeToDocumentMilliseconds(requestingDocument, finishTime))
81     , m_initiatorType(initiatorType)
82     , m_timing(response.networkLoadTiming())
83     , m_finishTime(finishTime)
84     , m_shouldReportDetails(passesTimingAllowCheck(response, requestingDocument))
85     , m_requestingDocument(requestingDocument)
86 {
87 }
88
89 PerformanceResourceTiming::~PerformanceResourceTiming()
90 {
91 }
92
93 AtomicString PerformanceResourceTiming::initiatorType() const
94 {
95     return m_initiatorType;
96 }
97
98 double PerformanceResourceTiming::redirectStart() const
99 {
100     // FIXME: Need to track and report redirects for resources.
101     if (!m_shouldReportDetails)
102         return 0.0;
103     return 0;
104 }
105
106 double PerformanceResourceTiming::redirectEnd() const
107 {
108     if (!m_shouldReportDetails)
109         return 0.0;
110     return 0;
111 }
112
113 double PerformanceResourceTiming::fetchStart() const
114 {
115     // FIXME: This should be different depending on redirects.
116     return (startTime());
117 }
118
119 double PerformanceResourceTiming::domainLookupStart() const
120 {
121     if (!m_shouldReportDetails)
122         return 0.0;
123
124     if (m_timing.domainLookupStart < 0)
125         return fetchStart();
126
127     return resourceTimeToDocumentMilliseconds(m_timing.domainLookupStart);
128 }
129
130 double PerformanceResourceTiming::domainLookupEnd() const
131 {
132     if (!m_shouldReportDetails)
133         return 0.0;
134
135     if (m_timing.domainLookupEnd < 0)
136         return domainLookupStart();
137
138     return resourceTimeToDocumentMilliseconds(m_timing.domainLookupEnd);
139 }
140
141 double PerformanceResourceTiming::connectStart() const
142 {
143     if (!m_shouldReportDetails)
144         return 0.0;
145
146     // connectStart will be -1 when a network request is not made.
147     if (m_timing.connectStart < 0)
148         return domainLookupEnd();
149
150     // connectStart includes any DNS time, so we may need to trim that off.
151     double connectStart = m_timing.connectStart;
152     if (m_timing.domainLookupEnd >= 0)
153         connectStart = m_timing.domainLookupEnd;
154
155     return resourceTimeToDocumentMilliseconds(connectStart);
156 }
157
158 double PerformanceResourceTiming::connectEnd() const
159 {
160     if (!m_shouldReportDetails)
161         return 0.0;
162
163     // connectStart will be -1 when a network request is not made.
164     if (m_timing.connectEnd < 0)
165         return connectStart();
166
167     return resourceTimeToDocumentMilliseconds(m_timing.connectEnd);
168 }
169
170 double PerformanceResourceTiming::secureConnectionStart() const
171 {
172     if (!m_shouldReportDetails)
173         return 0.0;
174
175     if (m_timing.secureConnectionStart < 0) // Secure connection not negotiated.
176         return 0.0;
177
178     return resourceTimeToDocumentMilliseconds(m_timing.secureConnectionStart);
179 }
180
181 double PerformanceResourceTiming::requestStart() const
182 {
183     if (!m_shouldReportDetails)
184         return 0.0;
185
186     return resourceTimeToDocumentMilliseconds(m_timing.requestStart);
187 }
188
189 double PerformanceResourceTiming::responseEnd() const
190 {
191     return monotonicTimeToDocumentMilliseconds(m_requestingDocument.get(), m_finishTime);
192 }
193
194 double PerformanceResourceTiming::resourceTimeToDocumentMilliseconds(double deltaMilliseconds) const
195 {
196     if (!deltaMilliseconds)
197         return 0.0;
198     double documentStartTime = m_requestingDocument->loader()->timing().monotonicTimeToZeroBasedDocumentTime(m_requestingDocument->loader()->timing().startTime()) * 1000.0;
199     double resourceTimeSeconds = (documentStartTime + deltaMilliseconds) / 1000.0;
200     return 1000.0 * Performance::reduceTimeResolution(resourceTimeSeconds);
201 }
202
203 } // namespace WebCore
204 #endif // ENABLE(WEB_TIMING)