1 | /* |
2 | * Copyright (C) 2016 Akamai Technologies Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
14 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
15 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
16 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
17 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
18 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
19 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
20 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
21 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | #include "ResourceTimingInformation.h" |
28 | |
29 | #include "CachedResource.h" |
30 | #include "DOMWindow.h" |
31 | #include "Document.h" |
32 | #include "Frame.h" |
33 | #include "FrameLoader.h" |
34 | #include "HTMLFrameOwnerElement.h" |
35 | #include "LoadTiming.h" |
36 | #include "Performance.h" |
37 | #include "ResourceTiming.h" |
38 | #include "RuntimeEnabledFeatures.h" |
39 | |
40 | namespace WebCore { |
41 | |
42 | bool ResourceTimingInformation::shouldAddResourceTiming(CachedResource& resource) |
43 | { |
44 | // FIXME: We can be less restrictive here. |
45 | // <https://github.com/w3c/resource-timing/issues/100> |
46 | if (!resource.resourceRequest().url().protocolIsInHTTPFamily()) |
47 | return false; |
48 | if (resource.response().httpStatusCode() >= 400) |
49 | return false; |
50 | if (resource.errorOccurred()) |
51 | return false; |
52 | if (resource.wasCanceled()) |
53 | return false; |
54 | |
55 | if (resource.options().loadedFromOpaqueSource == LoadedFromOpaqueSource::Yes) |
56 | return false; |
57 | |
58 | return true; |
59 | } |
60 | |
61 | void ResourceTimingInformation::addResourceTiming(CachedResource& resource, Document& document, ResourceTiming&& resourceTiming) |
62 | { |
63 | ASSERT(RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled()); |
64 | if (!ResourceTimingInformation::shouldAddResourceTiming(resource)) |
65 | return; |
66 | |
67 | auto iterator = m_initiatorMap.find(&resource); |
68 | if (iterator == m_initiatorMap.end()) |
69 | return; |
70 | |
71 | InitiatorInfo& info = iterator->value; |
72 | if (info.added == Added) |
73 | return; |
74 | |
75 | Document* initiatorDocument = &document; |
76 | if (resource.type() == CachedResource::Type::MainResource && document.frame() && document.frame()->loader().shouldReportResourceTimingToParentFrame()) |
77 | initiatorDocument = document.parentDocument(); |
78 | if (!initiatorDocument) |
79 | return; |
80 | |
81 | auto* initiatorWindow = initiatorDocument->domWindow(); |
82 | if (!initiatorWindow) |
83 | return; |
84 | |
85 | resourceTiming.overrideInitiatorName(info.name); |
86 | |
87 | initiatorWindow->performance().addResourceTiming(WTFMove(resourceTiming)); |
88 | |
89 | info.added = Added; |
90 | } |
91 | |
92 | void ResourceTimingInformation::storeResourceTimingInitiatorInformation(const CachedResourceHandle<CachedResource>& resource, const AtomicString& initiatorName, Frame* frame) |
93 | { |
94 | ASSERT(RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled()); |
95 | ASSERT(resource.get()); |
96 | |
97 | if (resource->type() == CachedResource::Type::MainResource) { |
98 | // <iframe>s should report the initial navigation requested by the parent document, but not subsequent navigations. |
99 | ASSERT(frame); |
100 | if (frame->ownerElement()) { |
101 | InitiatorInfo info = { frame->ownerElement()->localName(), NotYetAdded }; |
102 | m_initiatorMap.add(resource.get(), info); |
103 | } |
104 | } else { |
105 | InitiatorInfo info = { initiatorName, NotYetAdded }; |
106 | m_initiatorMap.add(resource.get(), info); |
107 | } |
108 | } |
109 | |
110 | } |
111 | |