| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "third_party/blink/renderer/core/timing/performance_navigation_timing.h" |
| |
| #include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h" |
| #include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h" |
| #include "third_party/blink/renderer/core/dom/document.h" |
| #include "third_party/blink/renderer/core/dom/document_timing.h" |
| #include "third_party/blink/renderer/core/frame/local_frame.h" |
| #include "third_party/blink/renderer/core/loader/document_load_timing.h" |
| #include "third_party/blink/renderer/core/loader/document_loader.h" |
| #include "third_party/blink/renderer/core/performance_entry_names.h" |
| #include "third_party/blink/renderer/core/timing/performance.h" |
| #include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h" |
| |
| namespace blink { |
| |
| PerformanceNavigationTiming::PerformanceNavigationTiming( |
| LocalFrame* frame, |
| ResourceTimingInfo* info, |
| TimeTicks time_origin, |
| const WebVector<WebServerTimingInfo>& server_timing) |
| : PerformanceResourceTiming( |
| info ? AtomicString(info->FinalResponse().Url().GetString()) |
| : g_empty_atom, |
| time_origin, |
| server_timing), |
| ContextClient(frame), |
| resource_timing_info_(info) { |
| DCHECK(frame); |
| DCHECK(info); |
| } |
| |
| PerformanceNavigationTiming::~PerformanceNavigationTiming() = default; |
| |
| AtomicString PerformanceNavigationTiming::entryType() const { |
| return performance_entry_names::kNavigation; |
| } |
| |
| PerformanceEntryType PerformanceNavigationTiming::EntryTypeEnum() const { |
| return PerformanceEntry::EntryType::kNavigation; |
| } |
| |
| void PerformanceNavigationTiming::Trace(blink::Visitor* visitor) { |
| ContextClient::Trace(visitor); |
| PerformanceResourceTiming::Trace(visitor); |
| } |
| |
| DocumentLoadTiming* PerformanceNavigationTiming::GetDocumentLoadTiming() const { |
| DocumentLoader* loader = GetDocumentLoader(); |
| if (!loader) |
| return nullptr; |
| |
| return &loader->GetTiming(); |
| } |
| |
| DocumentLoader* PerformanceNavigationTiming::GetDocumentLoader() const { |
| if (!GetFrame()) |
| return nullptr; |
| return GetFrame()->Loader().GetDocumentLoader(); |
| } |
| |
| const DocumentTiming* PerformanceNavigationTiming::GetDocumentTiming() const { |
| if (!GetFrame()) |
| return nullptr; |
| Document* document = GetFrame()->GetDocument(); |
| if (!document) |
| return nullptr; |
| |
| return &document->GetTiming(); |
| } |
| |
| ResourceLoadTiming* PerformanceNavigationTiming::GetResourceLoadTiming() const { |
| return resource_timing_info_->FinalResponse().GetResourceLoadTiming(); |
| } |
| |
| bool PerformanceNavigationTiming::AllowTimingDetails() const { |
| return true; |
| } |
| |
| bool PerformanceNavigationTiming::DidReuseConnection() const { |
| return resource_timing_info_->FinalResponse().ConnectionReused(); |
| } |
| |
| unsigned long long PerformanceNavigationTiming::GetTransferSize() const { |
| return resource_timing_info_->TransferSize(); |
| } |
| |
| unsigned long long PerformanceNavigationTiming::GetEncodedBodySize() const { |
| return resource_timing_info_->FinalResponse().EncodedBodyLength(); |
| } |
| |
| unsigned long long PerformanceNavigationTiming::GetDecodedBodySize() const { |
| return resource_timing_info_->FinalResponse().DecodedBodyLength(); |
| } |
| |
| AtomicString PerformanceNavigationTiming::GetNavigationType( |
| WebNavigationType type, |
| const Document* document) { |
| switch (type) { |
| case kWebNavigationTypeReload: |
| return "reload"; |
| case kWebNavigationTypeBackForward: |
| return "back_forward"; |
| case kWebNavigationTypeLinkClicked: |
| case kWebNavigationTypeFormSubmitted: |
| case kWebNavigationTypeFormResubmitted: |
| case kWebNavigationTypeOther: |
| return "navigate"; |
| } |
| NOTREACHED(); |
| return "navigate"; |
| } |
| |
| AtomicString PerformanceNavigationTiming::initiatorType() const { |
| return performance_entry_names::kNavigation; |
| } |
| |
| bool PerformanceNavigationTiming::GetAllowRedirectDetails() const { |
| ExecutionContext* context = GetFrame() ? GetFrame()->GetDocument() : nullptr; |
| const SecurityOrigin* security_origin = nullptr; |
| if (context) |
| security_origin = context->GetSecurityOrigin(); |
| if (!security_origin) |
| return false; |
| // TODO(sunjian): Think about how to make this flag deterministic. |
| // crbug/693183. |
| return Performance::AllowsTimingRedirect( |
| resource_timing_info_->RedirectChain(), |
| resource_timing_info_->FinalResponse(), *security_origin, context); |
| } |
| |
| AtomicString PerformanceNavigationTiming::AlpnNegotiatedProtocol() const { |
| return resource_timing_info_->FinalResponse().AlpnNegotiatedProtocol(); |
| } |
| |
| AtomicString PerformanceNavigationTiming::ConnectionInfo() const { |
| return resource_timing_info_->FinalResponse().ConnectionInfoString(); |
| } |
| |
| DOMHighResTimeStamp PerformanceNavigationTiming::unloadEventStart() const { |
| bool allow_redirect_details = GetAllowRedirectDetails(); |
| DocumentLoadTiming* timing = GetDocumentLoadTiming(); |
| |
| if (!allow_redirect_details || !timing || |
| !timing->HasSameOriginAsPreviousDocument()) |
| return 0; |
| return Performance::MonotonicTimeToDOMHighResTimeStamp( |
| TimeOrigin(), timing->UnloadEventStart(), |
| false /* allow_negative_value */); |
| } |
| |
| DOMHighResTimeStamp PerformanceNavigationTiming::unloadEventEnd() const { |
| bool allow_redirect_details = GetAllowRedirectDetails(); |
| DocumentLoadTiming* timing = GetDocumentLoadTiming(); |
| |
| if (!allow_redirect_details || !timing || |
| !timing->HasSameOriginAsPreviousDocument()) |
| return 0; |
| return Performance::MonotonicTimeToDOMHighResTimeStamp( |
| TimeOrigin(), timing->UnloadEventEnd(), false /* allow_negative_value */); |
| } |
| |
| DOMHighResTimeStamp PerformanceNavigationTiming::domInteractive() const { |
| const DocumentTiming* timing = GetDocumentTiming(); |
| if (!timing) |
| return 0.0; |
| return Performance::MonotonicTimeToDOMHighResTimeStamp( |
| TimeOrigin(), timing->DomInteractive(), false /* allow_negative_value */); |
| } |
| |
| DOMHighResTimeStamp PerformanceNavigationTiming::domContentLoadedEventStart() |
| const { |
| const DocumentTiming* timing = GetDocumentTiming(); |
| if (!timing) |
| return 0.0; |
| return Performance::MonotonicTimeToDOMHighResTimeStamp( |
| TimeOrigin(), timing->DomContentLoadedEventStart(), |
| false /* allow_negative_value */); |
| } |
| |
| DOMHighResTimeStamp PerformanceNavigationTiming::domContentLoadedEventEnd() |
| const { |
| const DocumentTiming* timing = GetDocumentTiming(); |
| if (!timing) |
| return 0.0; |
| return Performance::MonotonicTimeToDOMHighResTimeStamp( |
| TimeOrigin(), timing->DomContentLoadedEventEnd(), |
| false /* allow_negative_value */); |
| } |
| |
| DOMHighResTimeStamp PerformanceNavigationTiming::domComplete() const { |
| const DocumentTiming* timing = GetDocumentTiming(); |
| if (!timing) |
| return 0.0; |
| return Performance::MonotonicTimeToDOMHighResTimeStamp( |
| TimeOrigin(), timing->DomComplete(), false /* allow_negative_value */); |
| } |
| |
| DOMHighResTimeStamp PerformanceNavigationTiming::loadEventStart() const { |
| DocumentLoadTiming* timing = GetDocumentLoadTiming(); |
| if (!timing) |
| return 0.0; |
| return Performance::MonotonicTimeToDOMHighResTimeStamp( |
| TimeOrigin(), timing->LoadEventStart(), false /* allow_negative_value */); |
| } |
| |
| DOMHighResTimeStamp PerformanceNavigationTiming::loadEventEnd() const { |
| DocumentLoadTiming* timing = GetDocumentLoadTiming(); |
| if (!timing) |
| return 0.0; |
| return Performance::MonotonicTimeToDOMHighResTimeStamp( |
| TimeOrigin(), timing->LoadEventEnd(), false /* allow_negative_value */); |
| } |
| |
| AtomicString PerformanceNavigationTiming::type() const { |
| DocumentLoader* loader = GetDocumentLoader(); |
| if (GetFrame() && loader) |
| return GetNavigationType(loader->GetNavigationType(), |
| GetFrame()->GetDocument()); |
| return "navigate"; |
| } |
| |
| unsigned short PerformanceNavigationTiming::redirectCount() const { |
| bool allow_redirect_details = GetAllowRedirectDetails(); |
| DocumentLoadTiming* timing = GetDocumentLoadTiming(); |
| if (!allow_redirect_details || !timing) |
| return 0; |
| return timing->RedirectCount(); |
| } |
| |
| DOMHighResTimeStamp PerformanceNavigationTiming::redirectStart() const { |
| bool allow_redirect_details = GetAllowRedirectDetails(); |
| DocumentLoadTiming* timing = GetDocumentLoadTiming(); |
| if (!allow_redirect_details || !timing) |
| return 0; |
| return Performance::MonotonicTimeToDOMHighResTimeStamp( |
| TimeOrigin(), timing->RedirectStart(), false /* allow_negative_value */); |
| } |
| |
| DOMHighResTimeStamp PerformanceNavigationTiming::redirectEnd() const { |
| bool allow_redirect_details = GetAllowRedirectDetails(); |
| DocumentLoadTiming* timing = GetDocumentLoadTiming(); |
| if (!allow_redirect_details || !timing) |
| return 0; |
| return Performance::MonotonicTimeToDOMHighResTimeStamp( |
| TimeOrigin(), timing->RedirectEnd(), false /* allow_negative_value */); |
| } |
| |
| DOMHighResTimeStamp PerformanceNavigationTiming::fetchStart() const { |
| DocumentLoadTiming* timing = GetDocumentLoadTiming(); |
| if (!timing) |
| return 0.0; |
| return Performance::MonotonicTimeToDOMHighResTimeStamp( |
| TimeOrigin(), timing->FetchStart(), false /* allow_negative_value */); |
| } |
| |
| DOMHighResTimeStamp PerformanceNavigationTiming::responseEnd() const { |
| DocumentLoadTiming* timing = GetDocumentLoadTiming(); |
| if (!timing) |
| return 0.0; |
| return Performance::MonotonicTimeToDOMHighResTimeStamp( |
| TimeOrigin(), timing->ResponseEnd(), false /* allow_negative_value */); |
| } |
| |
| // Overriding PerformanceEntry's attributes. |
| DOMHighResTimeStamp PerformanceNavigationTiming::duration() const { |
| return loadEventEnd(); |
| } |
| |
| void PerformanceNavigationTiming::BuildJSONValue( |
| V8ObjectBuilder& builder) const { |
| PerformanceResourceTiming::BuildJSONValue(builder); |
| builder.AddNumber("unloadEventStart", unloadEventStart()); |
| builder.AddNumber("unloadEventEnd", unloadEventEnd()); |
| builder.AddNumber("domInteractive", domInteractive()); |
| builder.AddNumber("domContentLoadedEventStart", domContentLoadedEventStart()); |
| builder.AddNumber("domContentLoadedEventEnd", domContentLoadedEventEnd()); |
| builder.AddNumber("domComplete", domComplete()); |
| builder.AddNumber("loadEventStart", loadEventStart()); |
| builder.AddNumber("loadEventEnd", loadEventEnd()); |
| builder.AddString("type", type()); |
| builder.AddNumber("redirectCount", redirectCount()); |
| } |
| } |