1 /*
2  * Copyright (C) 2010. Adam Barth. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
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 Computer, 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.
16  *
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.
27  */
28 
29 #include "config.h"
30 #include "DocumentWriter.h"
31 
32 #include "DOMImplementation.h"
33 #include "DOMWindow.h"
34 #include "Frame.h"
35 #include "FrameLoader.h"
36 #include "FrameLoaderClient.h"
37 #include "FrameLoaderStateMachine.h"
38 #include "FrameView.h"
39 #include "PlaceholderDocument.h"
40 #include "PluginDocument.h"
41 #include "RawDataDocumentParser.h"
42 #include "ScriptableDocumentParser.h"
43 #include "SecurityOrigin.h"
44 #include "SegmentedString.h"
45 #include "Settings.h"
46 #include "SinkDocument.h"
47 #include "TextResourceDecoder.h"
48 
49 
50 namespace WebCore {
51 
canReferToParentFrameEncoding(const Frame * frame,const Frame * parentFrame)52 static inline bool canReferToParentFrameEncoding(const Frame* frame, const Frame* parentFrame)
53 {
54     return parentFrame && parentFrame->document()->securityOrigin()->canAccess(frame->document()->securityOrigin());
55 }
56 
DocumentWriter(Frame * frame)57 DocumentWriter::DocumentWriter(Frame* frame)
58     : m_frame(frame)
59     , m_receivedData(false)
60     , m_encodingWasChosenByUser(false)
61 {
62 }
63 
64 // This is only called by ScriptController::executeIfJavaScriptURL
65 // and always contains the result of evaluating a javascript: url.
66 // This is the <iframe src="javascript:'html'"> case.
replaceDocument(const String & source)67 void DocumentWriter::replaceDocument(const String& source)
68 {
69     m_frame->loader()->stopAllLoaders();
70     begin(m_frame->document()->url(), true, m_frame->document()->securityOrigin());
71 
72     if (!source.isNull()) {
73         if (!m_receivedData) {
74             m_receivedData = true;
75             m_frame->document()->setCompatibilityMode(Document::NoQuirksMode);
76         }
77 
78         // FIXME: This should call DocumentParser::appendBytes instead of append
79         // to support RawDataDocumentParsers.
80         if (DocumentParser* parser = m_frame->document()->parser())
81             parser->append(source);
82     }
83 
84     end();
85 }
86 
clear()87 void DocumentWriter::clear()
88 {
89     m_decoder = 0;
90     m_receivedData = false;
91     if (!m_encodingWasChosenByUser)
92         m_encoding = String();
93 }
94 
begin()95 void DocumentWriter::begin()
96 {
97     begin(KURL());
98 }
99 
createDocument(const KURL & url)100 PassRefPtr<Document> DocumentWriter::createDocument(const KURL& url)
101 {
102     if (!m_frame->loader()->stateMachine()->isDisplayingInitialEmptyDocument() && m_frame->loader()->client()->shouldUsePluginDocument(m_mimeType))
103         return PluginDocument::create(m_frame, url);
104     if (!m_frame->loader()->client()->hasHTMLView())
105         return PlaceholderDocument::create(m_frame, url);
106     return DOMImplementation::createDocument(m_mimeType, m_frame, url, m_frame->inViewSourceMode());
107 }
108 
begin(const KURL & urlReference,bool dispatch,SecurityOrigin * origin)109 void DocumentWriter::begin(const KURL& urlReference, bool dispatch, SecurityOrigin* origin)
110 {
111     // We need to take a reference to the security origin because |clear|
112     // might destroy the document that owns it.
113     RefPtr<SecurityOrigin> forcedSecurityOrigin = origin;
114 
115     // We grab a local copy of the URL because it's easy for callers to supply
116     // a URL that will be deallocated during the execution of this function.
117     // For example, see <https://bugs.webkit.org/show_bug.cgi?id=66360>.
118     KURL url = urlReference;
119 
120     // Create a new document before clearing the frame, because it may need to
121     // inherit an aliased security context.
122     RefPtr<Document> document = createDocument(url);
123 
124     // If the new document is for a Plugin but we're supposed to be sandboxed from Plugins,
125     // then replace the document with one whose parser will ignore the incoming data (bug 39323)
126     if (document->isPluginDocument() && m_frame->loader()->isSandboxed(SandboxPlugins))
127         document = SinkDocument::create(m_frame, url);
128 
129     // FIXME: Do we need to consult the content security policy here about blocked plug-ins?
130 
131     bool resetScripting = !(m_frame->loader()->stateMachine()->isDisplayingInitialEmptyDocument() && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));
132     m_frame->loader()->clear(resetScripting, resetScripting);
133     clear();
134     if (resetScripting)
135         m_frame->script()->updatePlatformScriptObjects();
136 
137     m_frame->loader()->setOutgoingReferrer(url);
138     m_frame->setDocument(document);
139 
140     if (m_decoder)
141         document->setDecoder(m_decoder.get());
142     if (forcedSecurityOrigin)
143         document->setSecurityOrigin(forcedSecurityOrigin.get());
144 
145     m_frame->domWindow()->setURL(document->url());
146     m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
147 
148     m_frame->loader()->didBeginDocument(dispatch);
149 
150     document->implicitOpen();
151 
152     if (m_frame->view() && m_frame->loader()->client()->hasHTMLView())
153         m_frame->view()->setContentsSize(IntSize());
154 }
155 
createDecoderIfNeeded()156 TextResourceDecoder* DocumentWriter::createDecoderIfNeeded()
157 {
158     if (!m_decoder) {
159         if (Settings* settings = m_frame->settings()) {
160             m_decoder = TextResourceDecoder::create(m_mimeType,
161                 settings->defaultTextEncodingName(),
162                 settings->usesEncodingDetector());
163             Frame* parentFrame = m_frame->tree()->parent();
164             // Set the hint encoding to the parent frame encoding only if
165             // the parent and the current frames share the security origin.
166             // We impose this condition because somebody can make a child frame
167             // containing a carefully crafted html/javascript in one encoding
168             // that can be mistaken for hintEncoding (or related encoding) by
169             // an auto detector. When interpreted in the latter, it could be
170             // an attack vector.
171             // FIXME: This might be too cautious for non-7bit-encodings and
172             // we may consider relaxing this later after testing.
173             if (canReferToParentFrameEncoding(m_frame, parentFrame))
174                 m_decoder->setHintEncoding(parentFrame->document()->decoder());
175         } else
176             m_decoder = TextResourceDecoder::create(m_mimeType, String());
177         Frame* parentFrame = m_frame->tree()->parent();
178         if (m_encoding.isEmpty()) {
179             if (canReferToParentFrameEncoding(m_frame, parentFrame))
180                 m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::EncodingFromParentFrame);
181         } else {
182             m_decoder->setEncoding(m_encoding,
183                 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
184         }
185         m_frame->document()->setDecoder(m_decoder.get());
186     }
187     return m_decoder.get();
188 }
189 
reportDataReceived()190 void DocumentWriter::reportDataReceived()
191 {
192     ASSERT(m_decoder);
193     if (!m_receivedData) {
194         m_receivedData = true;
195         if (m_decoder->encoding().usesVisualOrdering())
196             m_frame->document()->setVisuallyOrdered();
197         m_frame->document()->recalcStyle(Node::Force);
198     }
199 }
200 
addData(const char * str,int len,bool flush)201 void DocumentWriter::addData(const char* str, int len, bool flush)
202 {
203     if (len == -1)
204         len = strlen(str);
205 
206     DocumentParser* parser = m_frame->document()->parser();
207     if (parser)
208         parser->appendBytes(this, str, len, flush);
209 }
210 
end()211 void DocumentWriter::end()
212 {
213     m_frame->loader()->didEndDocument();
214     endIfNotLoadingMainResource();
215 }
216 
endIfNotLoadingMainResource()217 void DocumentWriter::endIfNotLoadingMainResource()
218 {
219     if (m_frame->loader()->isLoadingMainResource() || !m_frame->page() || !m_frame->document())
220         return;
221 
222     // http://bugs.webkit.org/show_bug.cgi?id=10854
223     // The frame's last ref may be removed and it can be deleted by checkCompleted(),
224     // so we'll add a protective refcount
225     RefPtr<Frame> protector(m_frame);
226 
227     // make sure nothing's left in there
228     addData(0, 0, true);
229     m_frame->document()->finishParsing();
230 }
231 
encoding() const232 String DocumentWriter::encoding() const
233 {
234     if (m_encodingWasChosenByUser && !m_encoding.isEmpty())
235         return m_encoding;
236     if (m_decoder && m_decoder->encoding().isValid())
237         return m_decoder->encoding().name();
238     Settings* settings = m_frame->settings();
239     return settings ? settings->defaultTextEncodingName() : String();
240 }
241 
setEncoding(const String & name,bool userChosen)242 void DocumentWriter::setEncoding(const String& name, bool userChosen)
243 {
244     m_frame->loader()->willSetEncoding();
245     m_encoding = name;
246     m_encodingWasChosenByUser = userChosen;
247 }
248 
setDecoder(TextResourceDecoder * decoder)249 void DocumentWriter::setDecoder(TextResourceDecoder* decoder)
250 {
251     m_decoder = decoder;
252 }
253 
deprecatedFrameEncoding() const254 String DocumentWriter::deprecatedFrameEncoding() const
255 {
256     return m_frame->document()->url().isEmpty() ? m_encoding : encoding();
257 }
258 
setDocumentWasLoadedAsPartOfNavigation()259 void DocumentWriter::setDocumentWasLoadedAsPartOfNavigation()
260 {
261     m_frame->document()->parser()->setDocumentWasLoadedAsPartOfNavigation();
262 }
263 
264 } // namespace WebCore
265