Source/WebCore: [Resource Timing] implementation of cross origin resouce timing restr...
[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(RESOURCE_TIMING)
36
37 #include "Document.h"
38 #include "DocumentLoadTiming.h"
39 #include "DocumentLoader.h"
40 #include "KURL.h"
41 #include "ResourceRequest.h"
42 #include "ResourceResponse.h"
43 #include "SecurityOrigin.h"
44 #include <wtf/Vector.h>
45
46 namespace WebCore {
47
48 static double monotonicTimeToDocumentMilliseconds(Document* document, double seconds)
49 {
50     ASSERT(seconds >= 0.0);
51     return document->loader()->timing()->monotonicTimeToZeroBasedDocumentTime(seconds) * 1000.0;
52 }
53
54 static bool passesTimingAllowCheck(const ResourceResponse& response, Document* requestingDocument)
55 {
56     AtomicallyInitializedStatic(AtomicString&, timingAllowOrigin = *new AtomicString("timing-allow-origin"));
57
58     const String& timingAllowOriginString = response.httpHeaderField(timingAllowOrigin);
59     if (timingAllowOriginString.isEmpty() || equalIgnoringCase(timingAllowOriginString, "null"))
60         return false;
61
62     if (timingAllowOriginString == "*")
63         return true;
64
65     const String& securityOrigin = requestingDocument->securityOrigin()->toString();
66     Vector<String> timingAllowOrigins;
67     timingAllowOriginString.split(" ", timingAllowOrigins);
68     for (size_t i = 0; i < timingAllowOrigins.size(); ++i)
69         if (timingAllowOrigins[i] == securityOrigin)
70             return true;
71
72     return false;
73 }
74
75 PerformanceResourceTiming::PerformanceResourceTiming(const AtomicString& initiatorType, const ResourceRequest& request, const ResourceResponse& response, double initiationTime, double finishTime, Document* requestingDocument)
76     : PerformanceEntry(request.url().string(), "resource", monotonicTimeToDocumentMilliseconds(requestingDocument, initiationTime), monotonicTimeToDocumentMilliseconds(requestingDocument, finishTime))
77     , m_initiatorType(initiatorType)
78     , m_timing(response.resourceLoadTiming())
79     , m_finishTime(finishTime)
80     , m_shouldReportDetails(passesTimingAllowCheck(response, requestingDocument))
81     , m_requestingDocument(requestingDocument)
82 {
83 }
84
85 PerformanceResourceTiming::~PerformanceResourceTiming()
86 {
87 }
88
89 AtomicString PerformanceResourceTiming::initiatorType() const
90 {
91     return m_initiatorType;
92 }
93
94 // FIXME: Need to enforce same-origin policy on these.
95
96 double PerformanceResourceTiming::redirectStart() const
97 {
98     // FIXME: Need to track and report redirects for resources.
99     if (!m_shouldReportDetails)
100         return 0.0;
101     return 0;
102 }
103
104 double PerformanceResourceTiming::redirectEnd() const
105 {
106     if (!m_shouldReportDetails)
107         return 0.0;
108     return 0;
109 }
110
111 double PerformanceResourceTiming::fetchStart() const
112 {
113     // FIXME: This should be different depending on redirects.
114     return (startTime());
115 }
116
117 double PerformanceResourceTiming::domainLookupStart() const
118 {
119     if (!m_shouldReportDetails)
120         return 0.0;
121
122     if (!m_timing || m_timing->dnsStart < 0)
123         return fetchStart();
124
125     return resourceTimeToDocumentMilliseconds(m_timing->dnsStart);
126 }
127
128 double PerformanceResourceTiming::domainLookupEnd() const
129 {
130     if (!m_shouldReportDetails)
131         return 0.0;
132
133     if (!m_timing || m_timing->dnsEnd < 0)
134         return domainLookupStart();
135
136     return resourceTimeToDocumentMilliseconds(m_timing->dnsEnd);
137 }
138
139 double PerformanceResourceTiming::connectStart() const
140 {
141     if (!m_shouldReportDetails)
142         return 0.0;
143
144     if (!m_timing || m_timing->connectStart < 0) // Connection was reused.
145         return domainLookupEnd();
146
147     // connectStart includes any DNS time, so we may need to trim that off.
148     int connectStart = m_timing->connectStart;
149     if (m_timing->dnsEnd >= 0)
150         connectStart = m_timing->dnsEnd;
151
152     return resourceTimeToDocumentMilliseconds(connectStart);
153 }
154
155 double PerformanceResourceTiming::connectEnd() const
156 {
157     if (!m_shouldReportDetails)
158         return 0.0;
159
160     if (!m_timing || m_timing->connectEnd < 0) // Connection was reused.
161         return connectStart();
162
163     return resourceTimeToDocumentMilliseconds(m_timing->connectEnd);
164 }
165
166 double PerformanceResourceTiming::secureConnectionStart() const
167 {
168     if (!m_shouldReportDetails)
169         return 0.0;
170
171     if (!m_timing || m_timing->sslStart < 0) // Secure connection not negotiated.
172         return 0.0;
173
174     return resourceTimeToDocumentMilliseconds(m_timing->sslStart);
175 }
176
177 double PerformanceResourceTiming::requestStart() const
178 {
179     if (!m_shouldReportDetails)
180         return 0.0;
181
182     if (!m_timing)
183         return connectEnd();
184
185     return resourceTimeToDocumentMilliseconds(m_timing->sendStart);
186 }
187
188 double PerformanceResourceTiming::responseStart() const
189 {
190     if (!m_shouldReportDetails)
191         return 0.0;
192
193     if (!m_timing)
194         return requestStart();
195     // FIXME: This number isn't exactly correct. See the notes in PerformanceTiming::responseStart().
196     return resourceTimeToDocumentMilliseconds(m_timing->receiveHeadersEnd);
197 }
198
199 double PerformanceResourceTiming::responseEnd() const
200 {
201     if (!m_shouldReportDetails)
202         return 0.0;
203
204     if (!m_timing)
205         return responseStart();
206
207     return monotonicTimeToDocumentMilliseconds(m_requestingDocument.get(), m_finishTime);
208 }
209
210 double PerformanceResourceTiming::resourceTimeToDocumentMilliseconds(int deltaMilliseconds) const
211 {
212     if (!deltaMilliseconds)
213         return 0.0;
214     return monotonicTimeToDocumentMilliseconds(m_requestingDocument.get(), m_timing->requestTime) + deltaMilliseconds;
215 }
216
217 } // namespace WebCore
218
219 #endif // ENABLE(RESOURCE_TIMING)