blob: a4b726bb84f2a249a71230d73ba758a2ca12581e [file] [log] [blame]
// Copyright 2017 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/dom/ClassicScript.h"
#include "bindings/core/v8/ScriptController.h"
#include "core/dom/Document.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/UseCounter.h"
#include "core/inspector/ConsoleMessage.h"
#include "platform/loader/fetch/AccessControlStatus.h"
#include "platform/network/mime/MIMETypeRegistry.h"
namespace blink {
namespace {
void LogScriptMIMEType(LocalFrame* frame,
ScriptResource* resource,
const String& mime_type,
const SecurityOrigin* security_origin) {
if (MIMETypeRegistry::IsSupportedJavaScriptMIMEType(mime_type))
return;
bool is_text = mime_type.StartsWith("text/", kTextCaseASCIIInsensitive);
if (is_text && MIMETypeRegistry::IsLegacySupportedJavaScriptLanguage(
mime_type.Substring(5)))
return;
bool is_same_origin = security_origin->CanRequest(resource->Url());
bool is_application =
!is_text &&
mime_type.StartsWith("application/", kTextCaseASCIIInsensitive);
UseCounter::Feature feature =
is_same_origin
? (is_text ? UseCounter::kSameOriginTextScript
: is_application ? UseCounter::kSameOriginApplicationScript
: UseCounter::kSameOriginOtherScript)
: (is_text
? UseCounter::kCrossOriginTextScript
: is_application ? UseCounter::kCrossOriginApplicationScript
: UseCounter::kCrossOriginOtherScript);
UseCounter::Count(frame, feature);
}
} // namespace
DEFINE_TRACE(ClassicScript) {
Script::Trace(visitor);
visitor->Trace(script_source_code_);
}
bool ClassicScript::IsEmpty() const {
return GetScriptSourceCode().IsEmpty();
}
bool ClassicScript::CheckMIMETypeBeforeRunScript(
Document* context_document,
const SecurityOrigin* security_origin) const {
ScriptResource* resource = GetScriptSourceCode().GetResource();
CHECK(resource);
if (!ScriptResource::MimeTypeAllowedByNosniff(resource->GetResponse())) {
context_document->AddConsoleMessage(ConsoleMessage::Create(
kSecurityMessageSource, kErrorMessageLevel,
"Refused to execute script from '" + resource->Url().ElidedString() +
"' because its MIME type ('" + resource->HttpContentType() +
"') is not executable, and "
"strict MIME type checking is "
"enabled."));
return false;
}
String mime_type = resource->HttpContentType();
LocalFrame* frame = context_document->GetFrame();
if (mime_type.StartsWith("image/") || mime_type == "text/csv" ||
mime_type.StartsWith("audio/") || mime_type.StartsWith("video/")) {
context_document->AddConsoleMessage(ConsoleMessage::Create(
kSecurityMessageSource, kErrorMessageLevel,
"Refused to execute script from '" + resource->Url().ElidedString() +
"' because its MIME type ('" + mime_type +
"') is not executable."));
if (mime_type.StartsWith("image/"))
UseCounter::Count(frame, UseCounter::kBlockedSniffingImageToScript);
else if (mime_type.StartsWith("audio/"))
UseCounter::Count(frame, UseCounter::kBlockedSniffingAudioToScript);
else if (mime_type.StartsWith("video/"))
UseCounter::Count(frame, UseCounter::kBlockedSniffingVideoToScript);
else if (mime_type == "text/csv")
UseCounter::Count(frame, UseCounter::kBlockedSniffingCSVToScript);
return false;
}
LogScriptMIMEType(frame, resource, mime_type, security_origin);
return true;
}
void ClassicScript::RunScript(LocalFrame* frame,
const SecurityOrigin* security_origin) const {
const bool is_external_script = GetScriptSourceCode().GetResource();
AccessControlStatus access_control_status = kNotSharableCrossOrigin;
if (!is_external_script) {
access_control_status = kSharableCrossOrigin;
} else {
CHECK(GetScriptSourceCode().GetResource());
access_control_status =
GetScriptSourceCode().GetResource()->CalculateAccessControlStatus(
security_origin);
}
frame->GetScriptController().ExecuteScriptInMainWorld(GetScriptSourceCode(),
access_control_status);
}
} // namespace blink