2 * Copyright (C) 2010. Adam Barth. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "DocumentWriter.h"
32 #include "DOMImplementation.h"
33 #include "DOMWindow.h"
35 #include "FrameLoader.h"
36 #include "FrameLoaderClient.h"
37 #include "FrameLoaderStateMachine.h"
38 #include "FrameView.h"
39 #include "MIMETypeRegistry.h"
40 #include "MainFrame.h"
41 #include "PluginDocument.h"
42 #include "RawDataDocumentParser.h"
43 #include "ScriptController.h"
44 #include "ScriptableDocumentParser.h"
45 #include "SecurityOrigin.h"
46 #include "SegmentedString.h"
48 #include "SinkDocument.h"
49 #include "TextResourceDecoder.h"
54 static inline bool canReferToParentFrameEncoding(const Frame* frame, const Frame* parentFrame)
56 return parentFrame && parentFrame->document()->securityOrigin()->canAccess(frame->document()->securityOrigin());
59 DocumentWriter::DocumentWriter(Frame* frame)
61 , m_hasReceivedSomeData(false)
62 , m_encodingWasChosenByUser(false)
63 , m_state(NotStartedWritingState)
67 // This is only called by ScriptController::executeIfJavaScriptURL
68 // and always contains the result of evaluating a javascript: url.
69 // This is the <iframe src="javascript:'html'"> case.
70 void DocumentWriter::replaceDocument(const String& source, Document* ownerDocument)
72 m_frame->loader().stopAllLoaders();
73 begin(m_frame->document()->url(), true, ownerDocument);
75 if (!source.isNull()) {
76 if (!m_hasReceivedSomeData) {
77 m_hasReceivedSomeData = true;
78 m_frame->document()->setCompatibilityMode(DocumentCompatibilityMode::NoQuirksMode);
81 // FIXME: This should call DocumentParser::appendBytes instead of append
82 // to support RawDataDocumentParsers.
83 if (DocumentParser* parser = m_frame->document()->parser())
84 parser->append(source.impl());
90 void DocumentWriter::clear()
93 m_hasReceivedSomeData = false;
94 if (!m_encodingWasChosenByUser)
95 m_encoding = String();
98 void DocumentWriter::begin()
103 PassRefPtr<Document> DocumentWriter::createDocument(const URL& url)
105 if (!m_frame->loader().stateMachine().isDisplayingInitialEmptyDocument() && m_frame->loader().client().shouldAlwaysUsePluginDocument(m_mimeType))
106 return PluginDocument::create(m_frame, url);
108 if (MIMETypeRegistry::isPDFMIMEType(m_mimeType) && (m_frame->isMainFrame() || !m_frame->settings().useImageDocumentForSubframePDF()))
109 return SinkDocument::create(m_frame, url);
111 if (!m_frame->loader().client().hasHTMLView())
112 return Document::createNonRenderedPlaceholder(m_frame, url);
113 return DOMImplementation::createDocument(m_mimeType, m_frame, url);
116 void DocumentWriter::begin(const URL& urlReference, bool dispatch, Document* ownerDocument)
118 // We grab a local copy of the URL because it's easy for callers to supply
119 // a URL that will be deallocated during the execution of this function.
120 // For example, see <https://bugs.webkit.org/show_bug.cgi?id=66360>.
121 URL url = urlReference;
123 // Create a new document before clearing the frame, because it may need to
124 // inherit an aliased security context.
125 RefPtr<Document> document = createDocument(url);
127 // If the new document is for a Plugin but we're supposed to be sandboxed from Plugins,
128 // then replace the document with one whose parser will ignore the incoming data (bug 39323)
129 if (document->isPluginDocument() && document->isSandboxed(SandboxPlugins))
130 document = SinkDocument::create(m_frame, url);
132 // FIXME: Do we need to consult the content security policy here about blocked plug-ins?
134 bool shouldReuseDefaultView = m_frame->loader().stateMachine().isDisplayingInitialEmptyDocument() && m_frame->document()->isSecureTransitionTo(url);
135 if (shouldReuseDefaultView)
136 document->takeDOMWindowFrom(m_frame->document());
138 document->createDOMWindow();
140 m_frame->loader().clear(document.get(), !shouldReuseDefaultView, !shouldReuseDefaultView);
143 if (!shouldReuseDefaultView)
144 m_frame->script().updatePlatformScriptObjects();
146 m_frame->loader().setOutgoingReferrer(url);
147 m_frame->setDocument(document);
150 document->setDecoder(m_decoder.get());
152 document->setCookieURL(ownerDocument->cookieURL());
153 document->setSecurityOrigin(ownerDocument->securityOrigin());
156 m_frame->loader().didBeginDocument(dispatch);
158 document->implicitOpen();
160 // We grab a reference to the parser so that we'll always send data to the
161 // original parser, even if the document acquires a new parser (e.g., via
163 m_parser = document->parser();
165 if (m_frame->view() && m_frame->loader().client().hasHTMLView())
166 m_frame->view()->setContentsSize(IntSize());
168 m_state = StartedWritingState;
171 TextResourceDecoder* DocumentWriter::createDecoderIfNeeded()
174 m_decoder = TextResourceDecoder::create(m_mimeType,
175 m_frame->settings().defaultTextEncodingName(),
176 m_frame->settings().usesEncodingDetector());
177 Frame* parentFrame = m_frame->tree().parent();
178 // Set the hint encoding to the parent frame encoding only if
179 // the parent and the current frames share the security origin.
180 // We impose this condition because somebody can make a child frame
181 // containing a carefully crafted html/javascript in one encoding
182 // that can be mistaken for hintEncoding (or related encoding) by
183 // an auto detector. When interpreted in the latter, it could be
185 // FIXME: This might be too cautious for non-7bit-encodings and
186 // we may consider relaxing this later after testing.
187 if (canReferToParentFrameEncoding(m_frame, parentFrame))
188 m_decoder->setHintEncoding(parentFrame->document()->decoder());
189 if (m_encoding.isEmpty()) {
190 if (canReferToParentFrameEncoding(m_frame, parentFrame))
191 m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::EncodingFromParentFrame);
193 m_decoder->setEncoding(m_encoding,
194 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
196 m_frame->document()->setDecoder(m_decoder.get());
198 return m_decoder.get();
201 void DocumentWriter::reportDataReceived()
204 if (m_hasReceivedSomeData)
206 m_hasReceivedSomeData = true;
207 if (m_decoder->encoding().usesVisualOrdering())
208 m_frame->document()->setVisuallyOrdered();
209 m_frame->document()->recalcStyle(Style::Force);
212 void DocumentWriter::addData(const char* bytes, size_t length)
214 // Check that we're inside begin()/end().
215 // FIXME: Change these to ASSERT once https://bugs.webkit.org/show_bug.cgi?id=80427 has
217 if (m_state == NotStartedWritingState)
219 if (m_state == FinishedWritingState)
223 m_parser->appendBytes(*this, bytes, length);
226 void DocumentWriter::end()
228 ASSERT(m_frame->page());
229 ASSERT(m_frame->document());
231 // The parser is guaranteed to be released after this point. begin() would
232 // have to be called again before we can start writing more data.
233 m_state = FinishedWritingState;
235 // http://bugs.webkit.org/show_bug.cgi?id=10854
236 // The frame's last ref may be removed and it can be deleted by checkCompleted(),
237 // so we'll add a protective refcount
238 Ref<Frame> protect(*m_frame);
242 // FIXME: m_parser->finish() should imply m_parser->flush().
243 m_parser->flush(*this);
250 void DocumentWriter::setEncoding(const String& name, bool userChosen)
253 m_encodingWasChosenByUser = userChosen;
256 void DocumentWriter::setDocumentWasLoadedAsPartOfNavigation()
258 ASSERT(m_parser && !m_parser->isStopped());
259 m_parser->setDocumentWasLoadedAsPartOfNavigation();
262 } // namespace WebCore