Move URL from WebCore to WTF
[WebKit-https.git] / Source / WebCore / page / PerformanceResourceTiming.cpp
index 0a3233b..7b7d87a 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
  * Copyright (C) 2012 Google Inc. All rights reserved.
  * Copyright (C) 2012 Intel Inc. All rights reserved.
  *
 #include "config.h"
 #include "PerformanceResourceTiming.h"
 
-#if ENABLE(WEB_TIMING)
-
 #include "Document.h"
 #include "DocumentLoader.h"
-#include "HTTPHeaderNames.h"
 #include "LoadTiming.h"
-#include "URL.h"
 #include "ResourceResponse.h"
-#include "SecurityOrigin.h"
-#include <wtf/Vector.h>
+#include "ResourceTiming.h"
+#include <wtf/URL.h>
 
 namespace WebCore {
 
-static double monotonicTimeToDocumentMilliseconds(Document* document, double seconds)
+static double monotonicTimeToDOMHighResTimeStamp(MonotonicTime timeOrigin, MonotonicTime timeStamp)
 {
-    ASSERT(seconds >= 0.0);
-    return Performance::reduceTimeResolution(document->loader()->timing().monotonicTimeToZeroBasedDocumentTime(seconds)) * 1000.0;
+    ASSERT(timeStamp.secondsSinceEpoch().seconds() >= 0);
+    if (!timeStamp || !timeOrigin)
+        return 0;
+
+    Seconds seconds = timeStamp - timeOrigin;
+    return Performance::reduceTimeResolution(seconds).milliseconds();
 }
 
-static bool passesTimingAllowCheck(const ResourceResponse& response, Document* requestingDocument)
+static double entryStartTime(MonotonicTime timeOrigin, const ResourceTiming& resourceTiming)
 {
-    Ref<SecurityOrigin> resourceOrigin = SecurityOrigin::create(response.url());
-    if (resourceOrigin->isSameSchemeHostPort(requestingDocument->securityOrigin()))
-        return true;
+    if (!resourceTiming.allowTimingDetails())
+        return monotonicTimeToDOMHighResTimeStamp(timeOrigin, resourceTiming.loadTiming().fetchStart());
 
-    const String& timingAllowOriginString = response.httpHeaderField(HTTPHeaderName::TimingAllowOrigin);
-    if (timingAllowOriginString.isEmpty() || equalLettersIgnoringASCIICase(timingAllowOriginString, "null"))
-        return false;
+    return monotonicTimeToDOMHighResTimeStamp(timeOrigin, resourceTiming.loadTiming().startTime());
+}
 
-    if (timingAllowOriginString == "*")
-        return true;
+static double entryEndTime(MonotonicTime timeOrigin, const ResourceTiming& resourceTiming)
+{
+    if (!resourceTiming.allowTimingDetails())
+        return entryStartTime(timeOrigin, resourceTiming);
 
-    const String& securityOrigin = requestingDocument->securityOrigin().toString();
-    Vector<String> timingAllowOrigins;
-    timingAllowOriginString.split(' ', timingAllowOrigins);
-    for (auto& origin : timingAllowOrigins) {
-        if (origin == securityOrigin)
-            return true;
+    if (resourceTiming.networkLoadMetrics().isComplete()) {
+        Seconds endTime = (resourceTiming.loadTiming().fetchStart() + resourceTiming.networkLoadMetrics().responseEnd) - timeOrigin;
+        return Performance::reduceTimeResolution(endTime).milliseconds();
     }
 
-    return false;
+    return monotonicTimeToDOMHighResTimeStamp(timeOrigin, resourceTiming.loadTiming().responseEnd());
 }
 
-PerformanceResourceTiming::PerformanceResourceTiming(const AtomicString& initiatorType, const URL& originalURL, const ResourceResponse& response, LoadTiming loadTiming, Document* requestingDocument)
-    : PerformanceEntry(originalURL.string(), ASCIILiteral("resource"), monotonicTimeToDocumentMilliseconds(requestingDocument, loadTiming.startTime()), monotonicTimeToDocumentMilliseconds(requestingDocument, loadTiming.responseEnd()))
-    , m_initiatorType(initiatorType)
-    , m_timing(response.networkLoadTiming())
-    , m_loadTiming(loadTiming)
-    , m_shouldReportDetails(passesTimingAllowCheck(response, requestingDocument))
-    , m_requestingDocument(requestingDocument)
+Ref<PerformanceResourceTiming> PerformanceResourceTiming::create(MonotonicTime timeOrigin, ResourceTiming&& resourceTiming)
 {
+    return adoptRef(*new PerformanceResourceTiming(timeOrigin, WTFMove(resourceTiming)));
 }
 
-PerformanceResourceTiming::~PerformanceResourceTiming()
+PerformanceResourceTiming::PerformanceResourceTiming(MonotonicTime timeOrigin, ResourceTiming&& resourceTiming)
+    : PerformanceEntry(PerformanceEntry::Type::Resource, resourceTiming.url().string(), "resource"_s, entryStartTime(timeOrigin, resourceTiming), entryEndTime(timeOrigin, resourceTiming))
+    , m_initiatorType(resourceTiming.initiator())
+    , m_timeOrigin(timeOrigin)
+    , m_loadTiming(resourceTiming.loadTiming())
+    , m_networkLoadMetrics(resourceTiming.networkLoadMetrics())
+    , m_shouldReportDetails(resourceTiming.allowTimingDetails())
+    , m_serverTiming(resourceTiming.populateServerTiming())
 {
+    m_networkLoadMetrics.clearNonTimingData();
 }
 
-AtomicString PerformanceResourceTiming::initiatorType() const
+PerformanceResourceTiming::~PerformanceResourceTiming() = default;
+
+String PerformanceResourceTiming::nextHopProtocol() const
 {
-    return m_initiatorType;
+    return m_networkLoadMetrics.protocol;
 }
 
 double PerformanceResourceTiming::workerStart() const
 {
+    // FIXME: <https://webkit.org/b/179377> Implement PerformanceResourceTiming.workerStart in ServiceWorkers
     return 0.0;
 }
 
@@ -104,7 +108,7 @@ double PerformanceResourceTiming::redirectStart() const
     if (!m_shouldReportDetails)
         return 0.0;
 
-    return monotonicTimeToDocumentMilliseconds(m_requestingDocument.get(), m_loadTiming.redirectStart());
+    return monotonicTimeToDOMHighResTimeStamp(m_timeOrigin, m_loadTiming.redirectStart());
 }
 
 double PerformanceResourceTiming::redirectEnd() const
@@ -112,12 +116,15 @@ double PerformanceResourceTiming::redirectEnd() const
     if (!m_shouldReportDetails)
         return 0.0;
 
-    return monotonicTimeToDocumentMilliseconds(m_requestingDocument.get(), m_loadTiming.redirectEnd());
+    return monotonicTimeToDOMHighResTimeStamp(m_timeOrigin, m_loadTiming.redirectEnd());
 }
 
 double PerformanceResourceTiming::fetchStart() const
 {
-    return monotonicTimeToDocumentMilliseconds(m_requestingDocument.get(), m_loadTiming.fetchStart());
+    // fetchStart is a required property.
+    ASSERT(m_loadTiming.fetchStart());
+
+    return monotonicTimeToDOMHighResTimeStamp(m_timeOrigin, m_loadTiming.fetchStart());
 }
 
 double PerformanceResourceTiming::domainLookupStart() const
@@ -125,10 +132,10 @@ double PerformanceResourceTiming::domainLookupStart() const
     if (!m_shouldReportDetails)
         return 0.0;
 
-    if (m_timing.domainLookupStart <= 0)
+    if (m_networkLoadMetrics.domainLookupStart <= 0_ms)
         return fetchStart();
 
-    return resourceTimeToDocumentMilliseconds(m_timing.domainLookupStart);
+    return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.domainLookupStart);
 }
 
 double PerformanceResourceTiming::domainLookupEnd() const
@@ -136,10 +143,10 @@ double PerformanceResourceTiming::domainLookupEnd() const
     if (!m_shouldReportDetails)
         return 0.0;
 
-    if (m_timing.domainLookupEnd <= 0)
+    if (m_networkLoadMetrics.domainLookupEnd <= 0_ms)
         return domainLookupStart();
 
-    return resourceTimeToDocumentMilliseconds(m_timing.domainLookupEnd);
+    return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.domainLookupEnd);
 }
 
 double PerformanceResourceTiming::connectStart() const
@@ -147,16 +154,10 @@ double PerformanceResourceTiming::connectStart() const
     if (!m_shouldReportDetails)
         return 0.0;
 
-    // connectStart will be -1 when a network request is not made.
-    if (m_timing.connectStart <= 0)
+    if (m_networkLoadMetrics.connectStart <= 0_ms)
         return domainLookupEnd();
 
-    // connectStart includes any DNS time, so we may need to trim that off.
-    double connectStart = m_timing.connectStart;
-    if (m_timing.domainLookupEnd >= 0)
-        connectStart = m_timing.domainLookupEnd;
-
-    return resourceTimeToDocumentMilliseconds(connectStart);
+    return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.connectStart);
 }
 
 double PerformanceResourceTiming::connectEnd() const
@@ -164,11 +165,10 @@ double PerformanceResourceTiming::connectEnd() const
     if (!m_shouldReportDetails)
         return 0.0;
 
-    // connectStart will be -1 when a network request is not made.
-    if (m_timing.connectEnd <= 0)
+    if (m_networkLoadMetrics.connectEnd <= 0_ms)
         return connectStart();
 
-    return resourceTimeToDocumentMilliseconds(m_timing.connectEnd);
+    return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.connectEnd);
 }
 
 double PerformanceResourceTiming::secureConnectionStart() const
@@ -176,10 +176,10 @@ double PerformanceResourceTiming::secureConnectionStart() const
     if (!m_shouldReportDetails)
         return 0.0;
 
-    if (m_timing.secureConnectionStart < 0) // Secure connection not negotiated.
+    if (m_networkLoadMetrics.secureConnectionStart <= 0_ms)
         return 0.0;
 
-    return resourceTimeToDocumentMilliseconds(m_timing.secureConnectionStart);
+    return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.secureConnectionStart);
 }
 
 double PerformanceResourceTiming::requestStart() const
@@ -187,7 +187,11 @@ double PerformanceResourceTiming::requestStart() const
     if (!m_shouldReportDetails)
         return 0.0;
 
-    return resourceTimeToDocumentMilliseconds(m_timing.requestStart);
+    // requestStart is 0 when a network request is not made.
+    if (m_networkLoadMetrics.requestStart <= 0_ms)
+        return connectEnd();
+
+    return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.requestStart);
 }
 
 double PerformanceResourceTiming::responseStart() const
@@ -195,27 +199,44 @@ double PerformanceResourceTiming::responseStart() const
     if (!m_shouldReportDetails)
         return 0.0;
 
-    return resourceTimeToDocumentMilliseconds(m_timing.responseStart);
+    // responseStart is 0 when a network request is not made.
+    if (m_networkLoadMetrics.responseStart <= 0_ms)
+        return requestStart();
+
+    return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.responseStart);
 }
 
 double PerformanceResourceTiming::responseEnd() const
 {
-    if (!m_shouldReportDetails)
-        return 0.0;
+    // responseEnd is a required property.
+    ASSERT(m_networkLoadMetrics.isComplete() || m_loadTiming.responseEnd());
+
+    if (m_networkLoadMetrics.isComplete()) {
+        // responseEnd is 0 when a network request is not made.
+        // This should mean all other properties are empty.
+        if (m_networkLoadMetrics.responseEnd <= 0_ms) {
+            ASSERT(m_networkLoadMetrics.responseStart <= 0_ms);
+            ASSERT(m_networkLoadMetrics.requestStart <= 0_ms);
+            ASSERT(m_networkLoadMetrics.requestStart <= 0_ms);
+            ASSERT(m_networkLoadMetrics.secureConnectionStart <= 0_ms);
+            ASSERT(m_networkLoadMetrics.connectEnd <= 0_ms);
+            ASSERT(m_networkLoadMetrics.connectStart <= 0_ms);
+            ASSERT(m_networkLoadMetrics.domainLookupEnd <= 0_ms);
+            ASSERT(m_networkLoadMetrics.domainLookupStart <= 0_ms);
+            return fetchStart();
+        }
+
+        return networkLoadTimeToDOMHighResTimeStamp(m_networkLoadMetrics.responseEnd);
+    }
 
-    return monotonicTimeToDocumentMilliseconds(m_requestingDocument.get(), m_loadTiming.responseEnd());
+    return monotonicTimeToDOMHighResTimeStamp(m_timeOrigin, m_loadTiming.responseEnd());
 }
 
-double PerformanceResourceTiming::resourceTimeToDocumentMilliseconds(double deltaMilliseconds) const
+double PerformanceResourceTiming::networkLoadTimeToDOMHighResTimeStamp(Seconds delta) const
 {
-    if (!deltaMilliseconds)
-        return 0.0;
-
-    double documentStartTime = m_requestingDocument->loader()->timing().monotonicTimeToZeroBasedDocumentTime(m_loadTiming.fetchStart()) * 1000.0;
-    double resourceTimeSeconds = (documentStartTime + deltaMilliseconds) / 1000.0;
-    return 1000.0 * Performance::reduceTimeResolution(resourceTimeSeconds);
+    ASSERT(delta);
+    Seconds final = (m_loadTiming.fetchStart() + delta) - m_timeOrigin;
+    return Performance::reduceTimeResolution(final).milliseconds();
 }
 
 } // namespace WebCore
-
-#endif // ENABLE(WEB_TIMING)