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 & url,bool dispatch,SecurityOrigin * origin)109 void DocumentWriter::begin(const KURL& url, 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 // Create a new document before clearing the frame, because it may need to
116 // inherit an aliased security context.
117 #if PLATFORM(ANDROID)
118 // Temporary hack for http://b/5188895
119 m_frame->setDocumentIsNotUpToDate();
120 #endif
121 RefPtr<Document> document = createDocument(url);
122
123 // If the new document is for a Plugin but we're supposed to be sandboxed from Plugins,
124 // then replace the document with one whose parser will ignore the incoming data (bug 39323)
125 if (document->isPluginDocument() && m_frame->loader()->isSandboxed(SandboxPlugins))
126 document = SinkDocument::create(m_frame, url);
127
128 // FIXME: Do we need to consult the content security policy here about blocked plug-ins?
129
130 bool resetScripting = !(m_frame->loader()->stateMachine()->isDisplayingInitialEmptyDocument() && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));
131 m_frame->loader()->clear(resetScripting, resetScripting);
132 clear();
133 if (resetScripting)
134 m_frame->script()->updatePlatformScriptObjects();
135
136 m_frame->loader()->setOutgoingReferrer(url);
137 m_frame->setDocument(document);
138
139 if (m_decoder)
140 document->setDecoder(m_decoder.get());
141 if (forcedSecurityOrigin)
142 document->setSecurityOrigin(forcedSecurityOrigin.get());
143
144 m_frame->domWindow()->setURL(document->url());
145 m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
146
147 m_frame->loader()->didBeginDocument(dispatch);
148
149 document->implicitOpen();
150
151 if (m_frame->view() && m_frame->loader()->client()->hasHTMLView())
152 m_frame->view()->setContentsSize(IntSize());
153 }
154
createDecoderIfNeeded()155 TextResourceDecoder* DocumentWriter::createDecoderIfNeeded()
156 {
157 if (!m_decoder) {
158 if (Settings* settings = m_frame->settings()) {
159 m_decoder = TextResourceDecoder::create(m_mimeType,
160 settings->defaultTextEncodingName(),
161 settings->usesEncodingDetector());
162 Frame* parentFrame = m_frame->tree()->parent();
163 // Set the hint encoding to the parent frame encoding only if
164 // the parent and the current frames share the security origin.
165 // We impose this condition because somebody can make a child frame
166 // containing a carefully crafted html/javascript in one encoding
167 // that can be mistaken for hintEncoding (or related encoding) by
168 // an auto detector. When interpreted in the latter, it could be
169 // an attack vector.
170 // FIXME: This might be too cautious for non-7bit-encodings and
171 // we may consider relaxing this later after testing.
172 if (canReferToParentFrameEncoding(m_frame, parentFrame))
173 m_decoder->setHintEncoding(parentFrame->document()->decoder());
174 } else
175 m_decoder = TextResourceDecoder::create(m_mimeType, String());
176 Frame* parentFrame = m_frame->tree()->parent();
177 if (m_encoding.isEmpty()) {
178 if (canReferToParentFrameEncoding(m_frame, parentFrame))
179 m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::EncodingFromParentFrame);
180 } else {
181 m_decoder->setEncoding(m_encoding,
182 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
183 }
184 m_frame->document()->setDecoder(m_decoder.get());
185 }
186 return m_decoder.get();
187 }
188
reportDataReceived()189 void DocumentWriter::reportDataReceived()
190 {
191 ASSERT(m_decoder);
192 if (!m_receivedData) {
193 m_receivedData = true;
194 if (m_decoder->encoding().usesVisualOrdering())
195 m_frame->document()->setVisuallyOrdered();
196 m_frame->document()->recalcStyle(Node::Force);
197 }
198 }
199
addData(const char * str,int len,bool flush)200 void DocumentWriter::addData(const char* str, int len, bool flush)
201 {
202 if (len == -1)
203 len = strlen(str);
204
205 DocumentParser* parser = m_frame->document()->parser();
206 if (parser)
207 parser->appendBytes(this, str, len, flush);
208 }
209
end()210 void DocumentWriter::end()
211 {
212 m_frame->loader()->didEndDocument();
213 endIfNotLoadingMainResource();
214 }
215
endIfNotLoadingMainResource()216 void DocumentWriter::endIfNotLoadingMainResource()
217 {
218 if (m_frame->loader()->isLoadingMainResource() || !m_frame->page() || !m_frame->document())
219 return;
220
221 // http://bugs.webkit.org/show_bug.cgi?id=10854
222 // The frame's last ref may be removed and it can be deleted by checkCompleted(),
223 // so we'll add a protective refcount
224 RefPtr<Frame> protector(m_frame);
225
226 // make sure nothing's left in there
227 addData(0, 0, true);
228 m_frame->document()->finishParsing();
229 }
230
encoding() const231 String DocumentWriter::encoding() const
232 {
233 if (m_encodingWasChosenByUser && !m_encoding.isEmpty())
234 return m_encoding;
235 if (m_decoder && m_decoder->encoding().isValid())
236 return m_decoder->encoding().name();
237 Settings* settings = m_frame->settings();
238 return settings ? settings->defaultTextEncodingName() : String();
239 }
240
setEncoding(const String & name,bool userChosen)241 void DocumentWriter::setEncoding(const String& name, bool userChosen)
242 {
243 m_frame->loader()->willSetEncoding();
244 m_encoding = name;
245 m_encodingWasChosenByUser = userChosen;
246 }
247
setDecoder(TextResourceDecoder * decoder)248 void DocumentWriter::setDecoder(TextResourceDecoder* decoder)
249 {
250 m_decoder = decoder;
251 }
252
deprecatedFrameEncoding() const253 String DocumentWriter::deprecatedFrameEncoding() const
254 {
255 return m_frame->document()->url().isEmpty() ? m_encoding : encoding();
256 }
257
setDocumentWasLoadedAsPartOfNavigation()258 void DocumentWriter::setDocumentWasLoadedAsPartOfNavigation()
259 {
260 m_frame->document()->parser()->setDocumentWasLoadedAsPartOfNavigation();
261 }
262
263 } // namespace WebCore
264