DocumentWriter.cpp [plain text]
#include "config.h"
#include "DocumentWriter.h"
#include "ContentSecurityPolicy.h"
#include "DOMImplementation.h"
#include "DOMWindow.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
#include "FrameLoaderStateMachine.h"
#include "FrameView.h"
#include "MIMETypeRegistry.h"
#include "MainFrame.h"
#include "PluginDocument.h"
#include "RawDataDocumentParser.h"
#include "ScriptController.h"
#include "ScriptableDocumentParser.h"
#include "SecurityOrigin.h"
#include "SecurityOriginPolicy.h"
#include "SegmentedString.h"
#include "Settings.h"
#include "SinkDocument.h"
#include "TextResourceDecoder.h"
#include <wtf/Ref.h>
namespace WebCore {
static inline bool canReferToParentFrameEncoding(const Frame* frame, const Frame* parentFrame)
{
return parentFrame && parentFrame->document()->securityOrigin()->canAccess(frame->document()->securityOrigin());
}
DocumentWriter::DocumentWriter(Frame* frame)
: m_frame(frame)
, m_hasReceivedSomeData(false)
, m_encodingWasChosenByUser(false)
, m_state(NotStartedWritingState)
{
}
void DocumentWriter::replaceDocument(const String& source, Document* ownerDocument)
{
m_frame->loader().stopAllLoaders();
if (m_frame->documentIsBeingReplaced())
return;
begin(m_frame->document()->url(), true, ownerDocument);
if (!m_frame->document())
return;
if (!source.isNull()) {
if (!m_hasReceivedSomeData) {
m_hasReceivedSomeData = true;
m_frame->document()->setCompatibilityMode(DocumentCompatibilityMode::NoQuirksMode);
}
if (DocumentParser* parser = m_frame->document()->parser())
parser->append(source.impl());
}
end();
}
void DocumentWriter::clear()
{
m_decoder = nullptr;
m_hasReceivedSomeData = false;
if (!m_encodingWasChosenByUser)
m_encoding = String();
}
void DocumentWriter::begin()
{
begin(URL());
}
Ref<Document> DocumentWriter::createDocument(const URL& url)
{
if (!m_frame->loader().stateMachine().isDisplayingInitialEmptyDocument() && m_frame->loader().client().shouldAlwaysUsePluginDocument(m_mimeType))
return PluginDocument::create(m_frame, url);
#if PLATFORM(IOS)
if (MIMETypeRegistry::isPDFMIMEType(m_mimeType) && (m_frame->isMainFrame() || !m_frame->settings().useImageDocumentForSubframePDF()))
return SinkDocument::create(m_frame, url);
#endif
if (!m_frame->loader().client().hasHTMLView())
return Document::createNonRenderedPlaceholder(m_frame, url);
return DOMImplementation::createDocument(m_mimeType, m_frame, url);
}
void DocumentWriter::begin(const URL& urlReference, bool dispatch, Document* ownerDocument)
{
URL url = urlReference;
Ref<Document> document = createDocument(url);
if (document->isPluginDocument() && document->isSandboxed(SandboxPlugins))
document = SinkDocument::create(m_frame, url);
bool shouldReuseDefaultView = m_frame->loader().stateMachine().isDisplayingInitialEmptyDocument() && m_frame->document()->isSecureTransitionTo(url);
if (shouldReuseDefaultView)
document->takeDOMWindowFrom(m_frame->document());
else
document->createDOMWindow();
HashSet<RefPtr<SecurityOrigin>> insecureNavigationRequestsToUpgrade;
if (auto* existingDocument = m_frame->document())
insecureNavigationRequestsToUpgrade = existingDocument->contentSecurityPolicy()->takeNavigationRequestsToUpgrade();
m_frame->loader().clear(document.ptr(), !shouldReuseDefaultView, !shouldReuseDefaultView);
clear();
if (!document->view())
return;
if (!shouldReuseDefaultView)
m_frame->script().updatePlatformScriptObjects();
m_frame->loader().setOutgoingReferrer(url);
m_frame->setDocument(document.copyRef());
document->contentSecurityPolicy()->setInsecureNavigationRequestsToUpgrade(WTFMove(insecureNavigationRequestsToUpgrade));
if (m_decoder)
document->setDecoder(m_decoder.get());
if (ownerDocument) {
document->setCookieURL(ownerDocument->cookieURL());
document->setSecurityOriginPolicy(ownerDocument->securityOriginPolicy());
document->setStrictMixedContentMode(ownerDocument->isStrictMixedContentMode());
}
m_frame->loader().didBeginDocument(dispatch);
document->implicitOpen();
m_parser = document->parser();
if (m_frame->view() && m_frame->loader().client().hasHTMLView())
m_frame->view()->setContentsSize(IntSize());
m_state = StartedWritingState;
}
TextResourceDecoder* DocumentWriter::createDecoderIfNeeded()
{
if (!m_decoder) {
m_decoder = TextResourceDecoder::create(m_mimeType,
m_frame->settings().defaultTextEncodingName(),
m_frame->settings().usesEncodingDetector());
Frame* parentFrame = m_frame->tree().parent();
if (canReferToParentFrameEncoding(m_frame, parentFrame))
m_decoder->setHintEncoding(parentFrame->document()->decoder());
if (m_encoding.isEmpty()) {
if (canReferToParentFrameEncoding(m_frame, parentFrame))
m_decoder->setEncoding(parentFrame->document()->textEncoding(), TextResourceDecoder::EncodingFromParentFrame);
} else {
m_decoder->setEncoding(m_encoding,
m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
}
m_frame->document()->setDecoder(m_decoder.get());
}
return m_decoder.get();
}
void DocumentWriter::reportDataReceived()
{
ASSERT(m_decoder);
if (m_hasReceivedSomeData)
return;
m_hasReceivedSomeData = true;
if (m_decoder->encoding().usesVisualOrdering())
m_frame->document()->setVisuallyOrdered();
m_frame->document()->recalcStyle(Style::Force);
}
void DocumentWriter::addData(const char* bytes, size_t length)
{
if (m_state == NotStartedWritingState)
CRASH();
if (m_state == FinishedWritingState)
CRASH();
ASSERT(m_parser);
m_parser->appendBytes(*this, bytes, length);
}
void DocumentWriter::end()
{
ASSERT(m_frame->page());
ASSERT(m_frame->document());
m_state = FinishedWritingState;
Ref<Frame> protect(*m_frame);
if (!m_parser)
return;
m_parser->flush(*this);
if (!m_parser)
return;
m_parser->finish();
m_parser = nullptr;
}
void DocumentWriter::setEncoding(const String& name, bool userChosen)
{
m_encoding = name;
m_encodingWasChosenByUser = userChosen;
}
void DocumentWriter::setDocumentWasLoadedAsPartOfNavigation()
{
ASSERT(m_parser && !m_parser->isStopped());
m_parser->setDocumentWasLoadedAsPartOfNavigation();
}
}