a14a03090bda8d1b2fed64ed246e918aa0e296b3
[WebKit-https.git] / Source / WebCore / loader / DocumentWriter.cpp
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
52 static inline bool canReferToParentFrameEncoding(const Frame* frame, const Frame* parentFrame) 
53 {
54     return parentFrame && parentFrame->document()->securityOrigin()->canAccess(frame->document()->securityOrigin());
55 }
56     
57 DocumentWriter::DocumentWriter(Frame* frame)
58     : m_frame(frame)
59     , m_hasReceivedSomeData(false)
60     , m_encodingWasChosenByUser(false)
61     , m_state(NotStartedWritingState)
62 {
63 }
64
65 // This is only called by ScriptController::executeIfJavaScriptURL
66 // and always contains the result of evaluating a javascript: url.
67 // This is the <iframe src="javascript:'html'"> case.
68 void DocumentWriter::replaceDocument(const String& source, Document* ownerDocument)
69 {
70     m_frame->loader()->stopAllLoaders();
71     begin(m_frame->document()->url(), true, ownerDocument);
72
73     if (!source.isNull()) {
74         if (!m_hasReceivedSomeData) {
75             m_hasReceivedSomeData = true;
76             m_frame->document()->setCompatibilityMode(Document::NoQuirksMode);
77         }
78
79         // FIXME: This should call DocumentParser::appendBytes instead of append
80         // to support RawDataDocumentParsers.
81         if (DocumentParser* parser = m_frame->document()->parser())
82             parser->append(source);
83     }
84
85     end();
86 }
87
88 void DocumentWriter::clear()
89 {
90     m_decoder = 0;
91     m_hasReceivedSomeData = false;
92     if (!m_encodingWasChosenByUser)
93         m_encoding = String();
94 }
95
96 void DocumentWriter::begin()
97 {
98     begin(KURL());
99 }
100
101 PassRefPtr<Document> DocumentWriter::createDocument(const KURL& url)
102 {
103     if (!m_frame->loader()->stateMachine()->isDisplayingInitialEmptyDocument() && m_frame->loader()->client()->shouldUsePluginDocument(m_mimeType))
104         return PluginDocument::create(m_frame, url);
105     if (!m_frame->loader()->client()->hasHTMLView())
106         return PlaceholderDocument::create(m_frame, url);
107     return DOMImplementation::createDocument(m_mimeType, m_frame, url, m_frame->inViewSourceMode());
108 }
109
110 void DocumentWriter::begin(const KURL& urlReference, bool dispatch, Document* ownerDocument)
111 {
112     // We grab a local copy of the URL because it's easy for callers to supply
113     // a URL that will be deallocated during the execution of this function.
114     // For example, see <https://bugs.webkit.org/show_bug.cgi?id=66360>.
115     KURL url = urlReference;
116
117     // Create a new document before clearing the frame, because it may need to
118     // inherit an aliased security context.
119     RefPtr<Document> document = createDocument(url);
120     
121     // If the new document is for a Plugin but we're supposed to be sandboxed from Plugins,
122     // then replace the document with one whose parser will ignore the incoming data (bug 39323)
123     if (document->isPluginDocument() && document->isSandboxed(SandboxPlugins))
124         document = SinkDocument::create(m_frame, url);
125
126     // FIXME: Do we need to consult the content security policy here about blocked plug-ins?
127
128     bool resetScripting = !(m_frame->loader()->stateMachine()->isDisplayingInitialEmptyDocument() && m_frame->document()->isSecureTransitionTo(url));
129     m_frame->loader()->clear(resetScripting, resetScripting);
130     clear();
131     if (resetScripting)
132         m_frame->script()->updatePlatformScriptObjects();
133
134     m_frame->loader()->setOutgoingReferrer(url);
135     m_frame->setDocument(document);
136
137     if (m_decoder)
138         document->setDecoder(m_decoder.get());
139     if (ownerDocument) {
140         document->setCookieURL(ownerDocument->cookieURL());
141         document->setSecurityOrigin(ownerDocument->securityOrigin());
142     }
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     // We grab a reference to the parser so that we'll always send data to the
152     // original parser, even if the document acquires a new parser (e.g., via
153     // document.open).
154     m_parser = document->parser();
155
156     if (m_frame->view() && m_frame->loader()->client()->hasHTMLView())
157         m_frame->view()->setContentsSize(IntSize());
158
159     m_state = StartedWritingState;
160 }
161
162 TextResourceDecoder* DocumentWriter::createDecoderIfNeeded()
163 {
164     if (!m_decoder) {
165         if (Settings* settings = m_frame->settings()) {
166             m_decoder = TextResourceDecoder::create(m_mimeType,
167                 settings->defaultTextEncodingName(),
168                 settings->usesEncodingDetector());
169             Frame* parentFrame = m_frame->tree()->parent();
170             // Set the hint encoding to the parent frame encoding only if
171             // the parent and the current frames share the security origin.
172             // We impose this condition because somebody can make a child frame 
173             // containing a carefully crafted html/javascript in one encoding
174             // that can be mistaken for hintEncoding (or related encoding) by
175             // an auto detector. When interpreted in the latter, it could be
176             // an attack vector.
177             // FIXME: This might be too cautious for non-7bit-encodings and
178             // we may consider relaxing this later after testing.
179             if (canReferToParentFrameEncoding(m_frame, parentFrame))
180                 m_decoder->setHintEncoding(parentFrame->document()->decoder());
181         } else
182             m_decoder = TextResourceDecoder::create(m_mimeType, String());
183         Frame* parentFrame = m_frame->tree()->parent();
184         if (m_encoding.isEmpty()) {
185             if (canReferToParentFrameEncoding(m_frame, parentFrame))
186                 m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::EncodingFromParentFrame);
187         } else {
188             m_decoder->setEncoding(m_encoding,
189                 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
190         }
191         m_frame->document()->setDecoder(m_decoder.get());
192     }
193     return m_decoder.get();
194 }
195
196 void DocumentWriter::reportDataReceived()
197 {
198     ASSERT(m_decoder);
199     if (m_hasReceivedSomeData)
200         return;
201     m_hasReceivedSomeData = true;
202     if (m_decoder->encoding().usesVisualOrdering())
203         m_frame->document()->setVisuallyOrdered();
204     m_frame->document()->recalcStyle(Node::Force);
205 }
206
207 void DocumentWriter::addData(const char* bytes, size_t length)
208 {
209     // Check that we're inside begin()/end().
210     // FIXME: Change these to ASSERT once https://bugs.webkit.org/show_bug.cgi?id=80427 has
211     // been resolved.
212     if (m_state == NotStartedWritingState)
213         CRASH();
214     if (m_state == FinishedWritingState)
215         CRASH();
216
217     ASSERT(m_parser);
218     m_parser->appendBytes(this, bytes, length);
219 }
220
221 void DocumentWriter::end()
222 {
223     ASSERT(m_frame->page());
224     ASSERT(m_frame->document());
225
226     // The parser is guaranteed to be released after this point. begin() would
227     // have to be called again before we can start writing more data.
228     m_state = FinishedWritingState;
229
230     // http://bugs.webkit.org/show_bug.cgi?id=10854
231     // The frame's last ref may be removed and it can be deleted by checkCompleted(), 
232     // so we'll add a protective refcount
233     RefPtr<Frame> protector(m_frame);
234
235     if (!m_parser)
236         return;
237     // FIXME: m_parser->finish() should imply m_parser->flush().
238     m_parser->flush(this);
239     if (!m_parser)
240         return;
241     m_parser->finish();
242     m_parser = 0;
243 }
244
245 void DocumentWriter::setEncoding(const String& name, bool userChosen)
246 {
247     m_frame->loader()->willSetEncoding();
248     m_encoding = name;
249     m_encodingWasChosenByUser = userChosen;
250 }
251
252 void DocumentWriter::setDocumentWasLoadedAsPartOfNavigation()
253 {
254     ASSERT(m_parser && !m_parser->isStopped());
255     m_parser->setDocumentWasLoadedAsPartOfNavigation();
256 }
257
258 } // namespace WebCore