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 "HTTPHeaderNames.h" 41#include "URL.h" 42#include "ResourceRequest.h" 43#include "ResourceResponse.h" 44#include "SecurityOrigin.h" 45#include <wtf/Vector.h> 46 47namespace WebCore { 48 49static double monotonicTimeToDocumentMilliseconds(Document* document, double seconds) 50{ 51 ASSERT(seconds >= 0.0); 52 return document->loader()->timing()->monotonicTimeToZeroBasedDocumentTime(seconds) * 1000.0; 53} 54 55static 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() || equalIgnoringCase(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 (size_t i = 0; i < timingAllowOrigins.size(); ++i) 72 if (timingAllowOrigins[i] == securityOrigin) 73 return true; 74 75 return false; 76} 77 78PerformanceResourceTiming::PerformanceResourceTiming(const AtomicString& initiatorType, const ResourceRequest& request, const ResourceResponse& response, double initiationTime, double finishTime, Document* requestingDocument) 79 : PerformanceEntry(request.url().string(), "resource", monotonicTimeToDocumentMilliseconds(requestingDocument, initiationTime), monotonicTimeToDocumentMilliseconds(requestingDocument, finishTime)) 80 , m_initiatorType(initiatorType) 81 , m_timing(response.resourceLoadTiming()) 82 , m_finishTime(finishTime) 83 , m_didReuseConnection(response.connectionReused()) 84 , m_shouldReportDetails(passesTimingAllowCheck(response, requestingDocument)) 85 , m_requestingDocument(requestingDocument) 86{ 87} 88 89PerformanceResourceTiming::~PerformanceResourceTiming() 90{ 91} 92 93AtomicString PerformanceResourceTiming::initiatorType() const 94{ 95 return m_initiatorType; 96} 97 98double 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 106double PerformanceResourceTiming::redirectEnd() const 107{ 108 if (!m_shouldReportDetails) 109 return 0.0; 110 return 0; 111} 112 113double PerformanceResourceTiming::fetchStart() const 114{ 115 // FIXME: This should be different depending on redirects. 116 return (startTime()); 117} 118 119double 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 130double 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 141double 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 || m_didReuseConnection) 148 return domainLookupEnd(); 149 150 // connectStart includes any DNS time, so we may need to trim that off. 151 int connectStart = m_timing.connectStart; 152 if (m_timing.domainLookupEnd >= 0) 153 connectStart = m_timing.domainLookupEnd; 154 155 return resourceTimeToDocumentMilliseconds(connectStart); 156} 157 158double 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 || m_didReuseConnection) 165 return connectStart(); 166 167 return resourceTimeToDocumentMilliseconds(m_timing.connectEnd); 168} 169 170double 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 181double PerformanceResourceTiming::requestStart() const 182{ 183 if (!m_shouldReportDetails) 184 return 0.0; 185 186 return resourceTimeToDocumentMilliseconds(m_timing.requestStart); 187} 188 189double PerformanceResourceTiming::responseEnd() const 190{ 191 return monotonicTimeToDocumentMilliseconds(m_requestingDocument.get(), m_finishTime); 192} 193 194double PerformanceResourceTiming::resourceTimeToDocumentMilliseconds(int deltaMilliseconds) const 195{ 196 if (!deltaMilliseconds) 197 return 0.0; 198 return monotonicTimeToDocumentMilliseconds(m_requestingDocument.get(), m_requestingDocument.get()->loader()->timing()->navigationStart()) + deltaMilliseconds; 199} 200 201} // namespace WebCore 202 203#endif // ENABLE(RESOURCE_TIMING) 204