blob: be3ff6ce8f27f0b5007ea48e9fed00ee7e6c67d9 [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/loader/modulescript/DocumentModuleScriptFetcher.h"
#include "core/dom/ExecutionContext.h"
#include "core/inspector/ConsoleMessage.h"
#include "core/loader/SubresourceIntegrityHelper.h"
#include "platform/loader/fetch/FetchUtils.h"
#include "platform/network/mime/MIMETypeRegistry.h"
namespace blink {
namespace {
bool WasModuleLoadSuccessful(
Resource* resource,
HeapVector<Member<ConsoleMessage>>* error_messages) {
// Implements conditions in Step 7 of
// https://html.spec.whatwg.org/#fetch-a-single-module-script
DCHECK(error_messages);
if (resource) {
SubresourceIntegrityHelper::GetConsoleMessages(
resource->IntegrityReportInfo(), error_messages);
}
// - response's type is "error"
if (!resource || resource->ErrorOccurred() ||
resource->IntegrityDisposition() !=
ResourceIntegrityDisposition::kPassed) {
return false;
}
const auto& response = resource->GetResponse();
// - response's status is not an ok status
if (response.IsHTTP() && !FetchUtils::IsOkStatus(response.HttpStatusCode())) {
return false;
}
// The result of extracting a MIME type from response's header list
// (ignoring parameters) is not a JavaScript MIME type
// Note: For historical reasons, fetching a classic script does not include
// MIME type checking. In contrast, module scripts will fail to load if they
// are not of a correct MIME type.
// We use ResourceResponse::HttpContentType() instead of MimeType(), as
// MimeType() may be rewritten by mime sniffer.
if (!MIMETypeRegistry::IsSupportedJavaScriptMIMEType(
response.HttpContentType())) {
String message =
"Failed to load module script: The server responded with a "
"non-JavaScript MIME type of \"" +
response.HttpContentType() +
"\". Strict MIME type checking is enforced for module scripts per "
"HTML spec.";
error_messages->push_back(ConsoleMessage::CreateForRequest(
kJSMessageSource, kErrorMessageLevel, message,
response.Url().GetString(), nullptr, resource->Identifier()));
return false;
}
return true;
}
} // namespace
DocumentModuleScriptFetcher::DocumentModuleScriptFetcher(
ResourceFetcher* fetcher)
: fetcher_(fetcher) {
DCHECK(fetcher_);
}
void DocumentModuleScriptFetcher::Fetch(FetchParameters& fetch_params,
ModuleScriptFetcher::Client* client) {
SetClient(client);
if (!ScriptResource::Fetch(fetch_params, fetcher_, this))
NotifyFinished(nullptr /* resource */);
}
void DocumentModuleScriptFetcher::NotifyFinished(Resource* resource) {
ClearResource();
ScriptResource* script_resource = ToScriptResource(resource);
HeapVector<Member<ConsoleMessage>> error_messages;
if (!WasModuleLoadSuccessful(script_resource, &error_messages)) {
Finalize(WTF::nullopt, error_messages);
return;
}
ModuleScriptCreationParams params(
script_resource->GetResponse().Url(), script_resource->SourceText(),
script_resource->GetResourceRequest().GetFetchCredentialsMode(),
script_resource->CalculateAccessControlStatus(
fetcher_->Context().GetSecurityOrigin()));
Finalize(params, error_messages);
}
void DocumentModuleScriptFetcher::Finalize(
const WTF::Optional<ModuleScriptCreationParams>& params,
const HeapVector<Member<ConsoleMessage>>& error_messages) {
NotifyFetchFinished(params, error_messages);
}
void DocumentModuleScriptFetcher::Trace(blink::Visitor* visitor) {
visitor->Trace(fetcher_);
ResourceClient::Trace(visitor);
ModuleScriptFetcher::Trace(visitor);
}
} // namespace blink