summaryrefslogtreecommitdiff
path: root/Source/WebCore/loader/ResourceLoadStatistics.cpp
diff options
context:
space:
mode:
authorKonstantin Tokarev <annulen@yandex.ru>2016-08-25 19:20:41 +0300
committerKonstantin Tokarev <annulen@yandex.ru>2017-02-02 12:30:55 +0000
commit6882a04fb36642862b11efe514251d32070c3d65 (patch)
treeb7959826000b061fd5ccc7512035c7478742f7b0 /Source/WebCore/loader/ResourceLoadStatistics.cpp
parentab6df191029eeeb0b0f16f127d553265659f739e (diff)
downloadqtwebkit-6882a04fb36642862b11efe514251d32070c3d65.tar.gz
Imported QtWebKit TP3 (git b57bc6801f1876c3220d5a4bfea33d620d477443)
Change-Id: I3b1d8a2808782c9f34d50240000e20cb38d3680f Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Source/WebCore/loader/ResourceLoadStatistics.cpp')
-rw-r--r--Source/WebCore/loader/ResourceLoadStatistics.cpp310
1 files changed, 310 insertions, 0 deletions
diff --git a/Source/WebCore/loader/ResourceLoadStatistics.cpp b/Source/WebCore/loader/ResourceLoadStatistics.cpp
new file mode 100644
index 000000000..de13a5f47
--- /dev/null
+++ b/Source/WebCore/loader/ResourceLoadStatistics.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ResourceLoadStatistics.h"
+
+#include "KeyedCoding.h"
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+static const unsigned minimumOriginsVisitedForPrevalenceClassification = 100;
+
+// Sub frame thresholds
+static const unsigned subframeUnderTopFrameOriginsThresholdAbsolute = 3;
+
+// Subresource thresholds
+static const unsigned subresourceUnderTopFrameOriginsThresholdAbsolute = 5;
+static const unsigned subresourceHasBeenRedirectedFromToUniqueDomainsThresholdAbsolute = 3;
+static const unsigned redirectedToOtherPrevalentResourceOriginsThresholdAbsolute = 2;
+
+bool ResourceLoadStatistics::checkAndSetAsPrevalentResourceIfNecessary(unsigned originsVisitedSoFar)
+{
+ if (originsVisitedSoFar < minimumOriginsVisitedForPrevalenceClassification || isPrevalentResource)
+ return false;
+
+ if (hasPrevalentResourceCharacteristics()) {
+ isPrevalentResource = true;
+ return true;
+ }
+
+ return false;
+}
+
+bool ResourceLoadStatistics::hasPrevalentResourceCharacteristics() const
+{
+ return subframeUnderTopFrameOrigins.size() > subframeUnderTopFrameOriginsThresholdAbsolute
+ || subresourceUnderTopFrameOrigins.size() > subresourceUnderTopFrameOriginsThresholdAbsolute
+ || subresourceUniqueRedirectsTo.size() > subresourceHasBeenRedirectedFromToUniqueDomainsThresholdAbsolute
+ || redirectedToOtherPrevalentResourceOrigins.size() > redirectedToOtherPrevalentResourceOriginsThresholdAbsolute;
+}
+
+typedef WTF::HashMap<String, unsigned, StringHash, HashTraits<String>, HashTraits<unsigned>>::KeyValuePairType ResourceLoadStatisticsValue;
+
+static void encodeHashCountedSet(KeyedEncoder& encoder, const String& label, const HashCountedSet<String>& hashCountedSet)
+{
+ if (hashCountedSet.isEmpty())
+ return;
+
+ encoder.encodeObjects(label, hashCountedSet.begin(), hashCountedSet.end(), [](KeyedEncoder& encoderInner, const ResourceLoadStatisticsValue& origin) {
+ encoderInner.encodeString("origin", origin.key);
+ encoderInner.encodeUInt32("count", origin.value);
+ });
+}
+
+void ResourceLoadStatistics::encode(KeyedEncoder& encoder, const String& origin) const
+{
+ encoder.encodeString("PrevalentResourceOrigin", origin);
+
+ // User interaction
+ encoder.encodeBool("hadUserInteraction", hadUserInteraction);
+
+ // Top frame stats
+ encoder.encodeBool("topFrameHasBeenNavigatedToBefore", topFrameHasBeenNavigatedToBefore);
+ encoder.encodeUInt32("topFrameHasBeenRedirectedTo", topFrameHasBeenRedirectedTo);
+ encoder.encodeUInt32("topFrameHasBeenRedirectedFrom", topFrameHasBeenRedirectedFrom);
+ encoder.encodeUInt32("topFrameInitialLoadCount", topFrameInitialLoadCount);
+ encoder.encodeUInt32("topFrameHasBeenNavigatedTo", topFrameHasBeenNavigatedTo);
+ encoder.encodeUInt32("topFrameHasBeenNavigatedFrom", topFrameHasBeenNavigatedFrom);
+
+ // Subframe stats
+ encoder.encodeBool("subframeHasBeenLoadedBefore", subframeHasBeenLoadedBefore);
+ encoder.encodeUInt32("subframeHasBeenRedirectedTo", subframeHasBeenRedirectedTo);
+ encoder.encodeUInt32("subframeHasBeenRedirectedFrom", subframeHasBeenRedirectedFrom);
+ encoder.encodeUInt32("subframeSubResourceCount", subframeSubResourceCount);
+ encodeHashCountedSet(encoder, "subframeUnderTopFrameOrigins", subframeUnderTopFrameOrigins);
+ encodeHashCountedSet(encoder, "subframeUniqueRedirectsTo", subframeUniqueRedirectsTo);
+ encoder.encodeUInt32("subframeHasBeenNavigatedTo", subframeHasBeenNavigatedTo);
+ encoder.encodeUInt32("subframeHasBeenNavigatedFrom", subframeHasBeenNavigatedFrom);
+
+ // Subresource stats
+ encoder.encodeUInt32("subresourceHasBeenRedirectedFrom", subresourceHasBeenRedirectedFrom);
+ encoder.encodeUInt32("subresourceHasBeenRedirectedTo", subresourceHasBeenRedirectedTo);
+ encoder.encodeUInt32("subresourceHasBeenSubresourceCount", subresourceHasBeenSubresourceCount);
+ encoder.encodeDouble("subresourceHasBeenSubresourceCountDividedByTotalNumberOfOriginsVisited", subresourceHasBeenSubresourceCountDividedByTotalNumberOfOriginsVisited);
+ encodeHashCountedSet(encoder, "subresourceUnderTopFrameOrigins", subresourceUnderTopFrameOrigins);
+ encodeHashCountedSet(encoder, "subresourceUniqueRedirectsTo", subresourceUniqueRedirectsTo);
+
+ // Prevalent Resource
+ encodeHashCountedSet(encoder, "redirectedToOtherPrevalentResourceOrigins", redirectedToOtherPrevalentResourceOrigins);
+ encoder.encodeBool("isPrevalentResource", isPrevalentResource);
+}
+
+static void decodeHashCountedSet(KeyedDecoder& decoder, const String& label, HashCountedSet<String>& hashCountedSet)
+{
+ Vector<String> ignore;
+ decoder.decodeObjects(label, ignore, [&hashCountedSet](KeyedDecoder& decoderInner, String& origin) {
+ if (!decoderInner.decodeString("origin", origin))
+ return false;
+
+ unsigned count;
+ if (!decoderInner.decodeUInt32("count", count))
+ return false;
+
+ hashCountedSet.add(origin, count);
+ return true;
+ });
+}
+
+bool ResourceLoadStatistics::decode(KeyedDecoder& decoder, const String& origin)
+{
+ String storedOrigin;
+ if (!decoder.decodeString("PrevalentResourceOrigin", storedOrigin))
+ return false;
+
+ ASSERT_UNUSED(origin, storedOrigin == origin);
+
+ // User interaction
+ if (!decoder.decodeBool("hadUserInteraction", hadUserInteraction))
+ return false;
+
+ // Top frame stats
+ if (!decoder.decodeBool("topFrameHasBeenNavigatedToBefore", topFrameHasBeenNavigatedToBefore))
+ return false;
+
+ if (!decoder.decodeUInt32("topFrameHasBeenRedirectedTo", topFrameHasBeenRedirectedTo))
+ return false;
+
+ if (!decoder.decodeUInt32("topFrameHasBeenRedirectedFrom", topFrameHasBeenRedirectedFrom))
+ return false;
+
+ if (!decoder.decodeUInt32("topFrameInitialLoadCount", topFrameInitialLoadCount))
+ return false;
+
+ if (!decoder.decodeUInt32("topFrameHasBeenNavigatedTo", topFrameHasBeenNavigatedTo))
+ return false;
+
+ if (!decoder.decodeUInt32("topFrameHasBeenNavigatedFrom", topFrameHasBeenNavigatedFrom))
+ return false;
+
+ // Subframe stats
+ if (!decoder.decodeBool("subframeHasBeenLoadedBefore", subframeHasBeenLoadedBefore))
+ return false;
+
+ if (!decoder.decodeUInt32("subframeHasBeenRedirectedTo", subframeHasBeenRedirectedTo))
+ return false;
+
+ if (!decoder.decodeUInt32("subframeHasBeenRedirectedFrom", subframeHasBeenRedirectedFrom))
+ return false;
+
+ if (!decoder.decodeUInt32("subframeSubResourceCount", subframeSubResourceCount))
+ return false;
+
+ decodeHashCountedSet(decoder, "subframeUnderTopFrameOrigins", subframeUnderTopFrameOrigins);
+ decodeHashCountedSet(decoder, "subframeUniqueRedirectsTo", subframeUniqueRedirectsTo);
+
+ if (!decoder.decodeUInt32("subframeHasBeenNavigatedTo", subframeHasBeenNavigatedTo))
+ return false;
+
+ if (!decoder.decodeUInt32("subframeHasBeenNavigatedFrom", subframeHasBeenNavigatedFrom))
+ return false;
+
+ // Subresource stats
+ if (!decoder.decodeUInt32("subresourceHasBeenRedirectedFrom", subresourceHasBeenRedirectedFrom))
+ return false;
+
+ if (!decoder.decodeUInt32("subresourceHasBeenRedirectedTo", subresourceHasBeenRedirectedTo))
+ return false;
+
+ if (!decoder.decodeUInt32("subresourceHasBeenSubresourceCount", subresourceHasBeenSubresourceCount))
+ return false;
+
+ if (!decoder.decodeDouble("subresourceHasBeenSubresourceCountDividedByTotalNumberOfOriginsVisited", subresourceHasBeenSubresourceCountDividedByTotalNumberOfOriginsVisited))
+ return false;
+
+ decodeHashCountedSet(decoder, "subresourceUnderTopFrameOrigins", subresourceUnderTopFrameOrigins);
+ decodeHashCountedSet(decoder, "subresourceUniqueRedirectsTo", subresourceUniqueRedirectsTo);
+
+ // Prevalent Resource
+ decodeHashCountedSet(decoder, "redirectedToOtherPrevalentResourceOrigins", redirectedToOtherPrevalentResourceOrigins);
+
+ if (!decoder.decodeBool("isPrevalentResource", isPrevalentResource))
+ return false;
+
+ return true;
+}
+
+static void appendBoolean(StringBuilder& builder, const String& label, bool flag)
+{
+ builder.append(" ");
+ builder.append(label);
+ builder.append(": ");
+ builder.append(flag ? "Yes" : "No");
+}
+
+static void appendHashCountedSet(StringBuilder& builder, const String& label, const HashCountedSet<String>& hashCountedSet)
+{
+ if (hashCountedSet.isEmpty())
+ return;
+
+ builder.append(" ");
+ builder.append(label);
+ builder.append(":\n");
+
+ for (auto& entry : hashCountedSet) {
+ builder.append(" ");
+ builder.append(entry.key);
+ builder.append(": ");
+ builder.appendNumber(entry.value);
+ builder.append('\n');
+ }
+
+}
+
+String ResourceLoadStatistics::toString() const
+{
+ StringBuilder builder;
+
+ // User interaction
+ appendBoolean(builder, "hadUserInteraction", hadUserInteraction);
+ builder.append('\n');
+
+ // Top frame stats
+ appendBoolean(builder, "topFrameHasBeenNavigatedToBefore", topFrameHasBeenNavigatedToBefore);
+ builder.append('\n');
+ builder.append(" topFrameHasBeenRedirectedTo: ");
+ builder.appendNumber(topFrameHasBeenRedirectedTo);
+ builder.append('\n');
+ builder.append(" topFrameHasBeenRedirectedFrom: ");
+ builder.appendNumber(topFrameHasBeenRedirectedFrom);
+ builder.append('\n');
+ builder.append(" topFrameInitialLoadCount: ");
+ builder.appendNumber(topFrameInitialLoadCount);
+ builder.append('\n');
+ builder.append(" topFrameHasBeenNavigatedTo: ");
+ builder.appendNumber(topFrameHasBeenNavigatedTo);
+ builder.append('\n');
+ builder.append(" topFrameHasBeenNavigatedFrom: ");
+ builder.appendNumber(topFrameHasBeenNavigatedFrom);
+ builder.append('\n');
+
+ // Subframe stats
+ appendBoolean(builder, "subframeHasBeenLoadedBefore", subframeHasBeenLoadedBefore);
+ builder.append('\n');
+ builder.append(" subframeHasBeenRedirectedTo: ");
+ builder.appendNumber(subframeHasBeenRedirectedTo);
+ builder.append('\n');
+ builder.append(" subframeHasBeenRedirectedFrom: ");
+ builder.appendNumber(subframeHasBeenRedirectedFrom);
+ builder.append('\n');
+ builder.append(" subframeSubResourceCount: ");
+ builder.appendNumber(subframeSubResourceCount);
+ builder.append('\n');
+ appendHashCountedSet(builder, "subframeUnderTopFrameOrigins", subframeUnderTopFrameOrigins);
+ appendHashCountedSet(builder, "subframeUniqueRedirectsTo", subframeUniqueRedirectsTo);
+ builder.append(" subframeHasBeenNavigatedTo: ");
+ builder.appendNumber(subframeHasBeenNavigatedTo);
+ builder.append('\n');
+ builder.append(" subframeHasBeenNavigatedFrom: ");
+ builder.appendNumber(subframeHasBeenNavigatedFrom);
+ builder.append('\n');
+
+ // Subresource stats
+ builder.append(" subresourceHasBeenRedirectedFrom: ");
+ builder.appendNumber(subresourceHasBeenRedirectedFrom);
+ builder.append('\n');
+ builder.append(" subresourceHasBeenRedirectedTo: ");
+ builder.appendNumber(subresourceHasBeenRedirectedTo);
+ builder.append('\n');
+ builder.append(" subresourceHasBeenSubresourceCount: ");
+ builder.appendNumber(subresourceHasBeenSubresourceCount);
+ builder.append('\n');
+ builder.append(" subresourceHasBeenSubresourceCountDividedByTotalNumberOfOriginsVisited: ");
+ builder.appendNumber(subresourceHasBeenSubresourceCountDividedByTotalNumberOfOriginsVisited);
+ builder.append('\n');
+ appendHashCountedSet(builder, "subresourceUnderTopFrameOrigins", subresourceUnderTopFrameOrigins);
+ appendHashCountedSet(builder, "subresourceUniqueRedirectsTo", subresourceUniqueRedirectsTo);
+
+ // Prevalent Resource
+ appendHashCountedSet(builder, "redirectedToOtherPrevalentResourceOrigins", redirectedToOtherPrevalentResourceOrigins);
+ appendBoolean(builder, "isPrevalentResource", isPrevalentResource);
+ builder.append('\n');
+
+ return builder.toString();
+}
+
+}