blob: a43dcce78e4862b4ae204db200020583f6cf9db8 [file] [log] [blame]
/*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2001 Dirk Mueller (mueller@kde.org)
* (C) 2006 Alexey Proskuryakov (ap@webkit.org)
* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All
* rights reserved.
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved.
* (http://www.torchmobile.com/)
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2013 Google Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "third_party/blink/renderer/core/dom/document_init.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_implementation.h"
#include "third_party/blink/renderer/core/dom/sink_document.h"
#include "third_party/blink/renderer/core/dom/xml_document.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/html/html_document.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/html/html_view_source_document.h"
#include "third_party/blink/renderer/core/html/image_document.h"
#include "third_party/blink/renderer/core/html/imports/html_imports_controller.h"
#include "third_party/blink/renderer/core/html/media/html_media_element.h"
#include "third_party/blink/renderer/core/html/media/media_document.h"
#include "third_party/blink/renderer/core/html/plugin_document.h"
#include "third_party/blink/renderer/core/html/text_document.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/plugin_data.h"
#include "third_party/blink/renderer/platform/network/mime/content_type.h"
#include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h"
#include "third_party/blink/renderer/platform/network/network_utils.h"
namespace blink {
// static
DocumentInit DocumentInit::Create() {
return DocumentInit();
}
DocumentInit::DocumentInit(const DocumentInit&) = default;
DocumentInit::~DocumentInit() = default;
DocumentInit& DocumentInit::ForTest() {
DCHECK(!execution_context_);
DCHECK(!window_);
#if DCHECK_IS_ON()
DCHECK(!for_test_);
for_test_ = true;
#endif
return *this;
}
DocumentInit& DocumentInit::WithImportsController(
HTMLImportsController* controller) {
imports_controller_ = controller;
return *this;
}
bool DocumentInit::ShouldSetURL() const {
return (window_ && !window_->GetFrame()->IsMainFrame()) || !url_.IsEmpty();
}
bool DocumentInit::IsSrcdocDocument() const {
return window_ && !window_->GetFrame()->IsMainFrame() && is_srcdoc_document_;
}
DocumentInit& DocumentInit::WithWindow(LocalDOMWindow* window,
Document* owner_document) {
DCHECK(!window_);
DCHECK(!execution_context_);
DCHECK(!imports_controller_);
#if DCHECK_IS_ON()
DCHECK(!for_test_);
#endif
DCHECK(window);
window_ = window;
execution_context_ = window;
owner_document_ = owner_document;
return *this;
}
DocumentInit& DocumentInit::ForInitialEmptyDocument(bool empty) {
is_initial_empty_document_ = empty;
return *this;
}
DocumentInit& DocumentInit::ForPrerendering(bool is_prerendering) {
is_prerendering_ = is_prerendering;
return *this;
}
// static
DocumentInit::Type DocumentInit::ComputeDocumentType(
LocalFrame* frame,
const KURL& url,
const String& mime_type,
bool* is_for_external_handler) {
if (frame && frame->InViewSourceMode())
return Type::kViewSource;
// Plugins cannot take HTML and XHTML from us, and we don't even need to
// initialize the plugin database for those.
if (mime_type == "text/html")
return Type::kHTML;
if (mime_type == "application/xhtml+xml")
return Type::kXHTML;
// multipart/x-mixed-replace is only supported for images.
if (MIMETypeRegistry::IsSupportedImageResourceMIMEType(mime_type) ||
mime_type == "multipart/x-mixed-replace") {
return Type::kImage;
}
if (HTMLMediaElement::GetSupportsType(ContentType(mime_type)))
return Type::kMedia;
if (frame && frame->GetPage() && frame->Loader().AllowPlugins()) {
PluginData* plugin_data = GetPluginData(frame, url);
// Everything else except text/plain can be overridden by plugins.
// Disallowing plugins to use text/plain prevents plugins from hijacking a
// fundamental type that the browser is expected to handle, and also serves
// as an optimization to prevent loading the plugin database in the common
// case.
if (mime_type != "text/plain" && plugin_data &&
plugin_data->SupportsMimeType(mime_type)) {
// Plugins handled by MimeHandlerView do not create a PluginDocument. They
// are rendered inside cross-process frames and the notion of a PluginView
// (which is associated with PluginDocument) is irrelevant here.
if (plugin_data->IsExternalPluginMimeType(mime_type)) {
if (is_for_external_handler)
*is_for_external_handler = true;
return Type::kHTML;
}
return Type::kPlugin;
}
}
if (MIMETypeRegistry::IsSupportedJavaScriptMIMEType(mime_type) ||
MIMETypeRegistry::IsJSONMimeType(mime_type) ||
MIMETypeRegistry::IsPlainTextMIMEType(mime_type)) {
return Type::kText;
}
if (mime_type == "image/svg+xml")
return Type::kSVG;
if (MIMETypeRegistry::IsXMLMIMEType(mime_type))
return Type::kXML;
return Type::kHTML;
}
// static
PluginData* DocumentInit::GetPluginData(LocalFrame* frame, const KURL& url) {
// If the document is being created for the main frame,
// frame()->tree().top()->securityContext() returns nullptr.
// For that reason, the origin must be retrieved directly from |url|.
if (frame->IsMainFrame())
return frame->GetPage()->GetPluginData(SecurityOrigin::Create(url).get());
const SecurityOrigin* main_frame_origin =
frame->Tree().Top().GetSecurityContext()->GetSecurityOrigin();
return frame->GetPage()->GetPluginData(main_frame_origin);
}
DocumentInit& DocumentInit::WithTypeFrom(const String& mime_type) {
mime_type_ = mime_type;
type_ = ComputeDocumentType(window_ ? window_->GetFrame() : nullptr, Url(),
mime_type_, &is_for_external_handler_);
return *this;
}
DocumentInit& DocumentInit::WithExecutionContext(
ExecutionContext* execution_context) {
DCHECK(!execution_context_);
DCHECK(!window_);
#if DCHECK_IS_ON()
DCHECK(!for_test_);
#endif
execution_context_ = execution_context;
return *this;
}
DocumentInit& DocumentInit::WithURL(const KURL& url) {
DCHECK(url_.IsNull());
url_ = url;
return *this;
}
const KURL& DocumentInit::GetCookieUrl() const {
const KURL& cookie_url =
owner_document_ ? owner_document_->CookieURL() : url_;
// An "about:blank" should inherit the `cookie_url` from the initiator of the
// navigation, but sometimes "about:blank" may commit without an
// `owner_document` (e.g. if the original initiator has been navigated away).
// In such scenario, it is important to use a safe `cookie_url` (e.g.
// kCookieAverseUrl) to avoid triggering mojo::ReportBadMessage and renderer
// kills via RestrictedCookieManager::ValidateAccessToCookiesAt.
//
// TODO(https://crbug.com/1176291): Correctly inherit the `cookie_url` from
// the initiator.
if (cookie_url.IsAboutBlankURL()) {
// Signify a cookie-averse document [1] with an null URL. See how
// CookiesJar::GetCookies and other methods check `cookie_url` against
// KURL::IsEmpty.
//
// [1] https://html.spec.whatwg.org/#cookie-averse-document-object
const KURL& kCookieAverseUrl = NullURL();
return kCookieAverseUrl;
}
return cookie_url;
}
DocumentInit& DocumentInit::WithSrcdocDocument(bool is_srcdoc_document) {
is_srcdoc_document_ = is_srcdoc_document;
return *this;
}
DocumentInit& DocumentInit::WithWebBundleClaimedUrl(
const KURL& web_bundle_claimed_url) {
web_bundle_claimed_url_ = web_bundle_claimed_url;
return *this;
}
DocumentInit& DocumentInit::WithUkmSourceId(ukm::SourceId ukm_source_id) {
ukm_source_id_ = ukm_source_id;
return *this;
}
Document* DocumentInit::CreateDocument() const {
#if DCHECK_IS_ON()
DCHECK(execution_context_ || for_test_);
#endif
switch (type_) {
case Type::kHTML:
return MakeGarbageCollected<HTMLDocument>(*this);
case Type::kXHTML:
return XMLDocument::CreateXHTML(*this);
case Type::kImage:
return MakeGarbageCollected<ImageDocument>(*this);
case Type::kPlugin: {
DCHECK(window_);
if (window_->IsSandboxed(
network::mojom::blink::WebSandboxFlags::kPlugins)) {
return MakeGarbageCollected<SinkDocument>(*this);
}
return MakeGarbageCollected<PluginDocument>(*this);
}
case Type::kMedia:
return MakeGarbageCollected<MediaDocument>(*this);
case Type::kSVG:
return XMLDocument::CreateSVG(*this);
case Type::kXML:
return MakeGarbageCollected<XMLDocument>(*this);
case Type::kViewSource:
return MakeGarbageCollected<HTMLViewSourceDocument>(*this);
case Type::kText:
return MakeGarbageCollected<TextDocument>(*this);
case Type::kUnspecified:
FALLTHROUGH;
default:
break;
}
NOTREACHED();
return nullptr;
}
} // namespace blink