blob: 975e84283c6b3c5c4f7bb8b6f633e4566e26a67e [file] [log] [blame]
// Copyright 2015 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 "core/frame/HostsUsingFeatures.h"
#include "bindings/core/v8/ScriptState.h"
#include "core/dom/Document.h"
#include "core/frame/LocalDOMWindow.h"
#include "core/page/Page.h"
#include "public/platform/Platform.h"
namespace blink {
HostsUsingFeatures::~HostsUsingFeatures()
{
updateMeasurementsAndClear();
}
HostsUsingFeatures::Value::Value()
: m_countBits(0)
{
}
void HostsUsingFeatures::countAnyWorld(Document& document, Feature feature)
{
document.HostsUsingFeaturesValue().count(feature);
}
void HostsUsingFeatures::countMainWorldOnly(const ScriptState* scriptState, Document& document, Feature feature)
{
if (!scriptState || !scriptState->world().isMainWorld())
return;
countAnyWorld(document, feature);
}
static Document* documentFromEventTarget(EventTarget& target)
{
ExecutionContext* executionContext = target.getExecutionContext();
if (!executionContext)
return nullptr;
if (executionContext->isDocument())
return toDocument(executionContext);
if (LocalDOMWindow* executingWindow = executionContext->executingWindow())
return executingWindow->document();
return nullptr;
}
void HostsUsingFeatures::countHostOrIsolatedWorldHumanReadableName(const ScriptState* scriptState, EventTarget& target, Feature feature)
{
if (!scriptState)
return;
Document* document = documentFromEventTarget(target);
if (!document)
return;
if (scriptState->world().isMainWorld()) {
document->HostsUsingFeaturesValue().count(feature);
return;
}
if (Page* page = document->page())
page->hostsUsingFeatures().countName(feature, scriptState->world().isolatedWorldHumanReadableName());
}
void HostsUsingFeatures::Value::count(Feature feature)
{
DCHECK(feature < Feature::NumberOfFeatures);
m_countBits |= 1 << static_cast<unsigned>(feature);
}
void HostsUsingFeatures::countName(Feature feature, const String& name)
{
auto result = m_valueByName.add(name, Value());
result.storedValue->value.count(feature);
}
void HostsUsingFeatures::clear()
{
m_valueByName.clear();
m_urlAndValues.clear();
}
void HostsUsingFeatures::documentDetached(Document& document)
{
HostsUsingFeatures::Value counter = document.HostsUsingFeaturesValue();
if (counter.isEmpty())
return;
const KURL& url = document.url();
if (!url.protocolIsInHTTPFamily())
return;
m_urlAndValues.append(std::make_pair(url, counter));
document.HostsUsingFeaturesValue().clear();
DCHECK(document.HostsUsingFeaturesValue().isEmpty());
}
void HostsUsingFeatures::updateMeasurementsAndClear()
{
if (!m_urlAndValues.isEmpty()) {
recordHostToRappor();
recordETLDPlus1ToRappor();
m_urlAndValues.clear();
}
if (!m_valueByName.isEmpty())
recordNamesToRappor();
}
void HostsUsingFeatures::recordHostToRappor()
{
DCHECK(!m_urlAndValues.isEmpty());
// Aggregate values by hosts.
HashMap<String, HostsUsingFeatures::Value> aggregatedByHost;
for (const auto& urlAndValue : m_urlAndValues) {
DCHECK(!urlAndValue.first.isEmpty());
auto result = aggregatedByHost.add(urlAndValue.first.host(), urlAndValue.second);
if (!result.isNewEntry)
result.storedValue->value.aggregate(urlAndValue.second);
}
// Report to RAPPOR.
for (auto& hostAndValue : aggregatedByHost)
hostAndValue.value.recordHostToRappor(hostAndValue.key);
}
void HostsUsingFeatures::recordETLDPlus1ToRappor()
{
DCHECK(!m_urlAndValues.isEmpty());
// Aggregate values by URL.
HashMap<String, HostsUsingFeatures::Value> aggregatedByURL;
for (const auto& urlAndValue : m_urlAndValues) {
DCHECK(!urlAndValue.first.isEmpty());
auto result = aggregatedByURL.add(urlAndValue.first, urlAndValue.second);
if (!result.isNewEntry)
result.storedValue->value.aggregate(urlAndValue.second);
}
// Report to RAPPOR.
for (auto& urlAndValue : aggregatedByURL)
urlAndValue.value.recordETLDPlus1ToRappor(KURL(ParsedURLString, urlAndValue.key));
}
void HostsUsingFeatures::recordNamesToRappor()
{
DCHECK(!m_valueByName.isEmpty());
for (auto& nameAndValue : m_valueByName)
nameAndValue.value.recordNameToRappor(nameAndValue.key);
m_valueByName.clear();
}
void HostsUsingFeatures::Value::aggregate(HostsUsingFeatures::Value other)
{
m_countBits |= other.m_countBits;
}
void HostsUsingFeatures::Value::recordHostToRappor(const String& host)
{
if (get(Feature::ElementCreateShadowRoot))
Platform::current()->recordRappor("WebComponents.ElementCreateShadowRoot", host);
if (get(Feature::ElementAttachShadow))
Platform::current()->recordRappor("WebComponents.ElementAttachShadow", host);
if (get(Feature::DocumentRegisterElement))
Platform::current()->recordRappor("WebComponents.DocumentRegisterElement", host);
if (get(Feature::EventPath))
Platform::current()->recordRappor("WebComponents.EventPath", host);
if (get(Feature::DeviceMotionInsecureHost))
Platform::current()->recordRappor("PowerfulFeatureUse.Host.DeviceMotion.Insecure", host);
if (get(Feature::DeviceOrientationInsecureHost))
Platform::current()->recordRappor("PowerfulFeatureUse.Host.DeviceOrientation.Insecure", host);
if (get(Feature::FullscreenInsecureHost))
Platform::current()->recordRappor("PowerfulFeatureUse.Host.Fullscreen.Insecure", host);
if (get(Feature::GeolocationInsecureHost))
Platform::current()->recordRappor("PowerfulFeatureUse.Host.Geolocation.Insecure", host);
if (get(Feature::ApplicationCacheManifestSelectInsecureHost))
Platform::current()->recordRappor("PowerfulFeatureUse.Host.ApplicationCacheManifestSelect.Insecure", host);
if (get(Feature::ApplicationCacheAPIInsecureHost))
Platform::current()->recordRappor("PowerfulFeatureUse.Host.ApplicationCacheAPI.Insecure", host);
}
void HostsUsingFeatures::Value::recordNameToRappor(const String& name)
{
if (get(Feature::EventPath))
Platform::current()->recordRappor("WebComponents.EventPath.Extensions", name);
}
void HostsUsingFeatures::Value::recordETLDPlus1ToRappor(const KURL& url)
{
if (get(Feature::GetUserMediaInsecureHost))
Platform::current()->recordRapporURL("PowerfulFeatureUse.ETLDPlus1.GetUserMedia.Insecure", WebURL(url));
if (get(Feature::GetUserMediaSecureHost))
Platform::current()->recordRapporURL("PowerfulFeatureUse.ETLDPlus1.GetUserMedia.Secure", WebURL(url));
}
} // namespace blink