blob: 005be4d2d2e17808ef82a3b93d293d878a19a093 [file] [log] [blame]
abarth@webkit.org412c54e2010-04-20 22:12:16 +00001/*
2 * Copyright (C) 2010. Adam Barth. All rights reserved.
bfulgham@apple.com01c956f2016-08-16 20:32:57 +00003 * Copyright (C) 2016 Apple Inc. All rights reserved.
abarth@webkit.org412c54e2010-04-20 22:12:16 +00004 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
mjs@apple.com92047332014-03-15 04:08:27 +000014 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
abarth@webkit.org412c54e2010-04-20 22:12:16 +000015 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "config.h"
31#include "DocumentWriter.h"
32
bfulgham@apple.comb30d7f82016-06-07 15:47:30 +000033#include "ContentSecurityPolicy.h"
abarth@webkit.org412c54e2010-04-20 22:12:16 +000034#include "DOMImplementation.h"
abarth@webkit.org37bf5532010-04-20 22:26:44 +000035#include "DOMWindow.h"
abarth@webkit.org412c54e2010-04-20 22:12:16 +000036#include "Frame.h"
37#include "FrameLoader.h"
38#include "FrameLoaderClient.h"
japhet@chromium.org61d4b9c2010-06-21 20:06:02 +000039#include "FrameLoaderStateMachine.h"
abarth@webkit.org412c54e2010-04-20 22:12:16 +000040#include "FrameView.h"
timothy_horton@apple.com12105542014-06-18 01:35:32 +000041#include "MIMETypeRegistry.h"
42#include "MainFrame.h"
abarth@webkit.org412c54e2010-04-20 22:12:16 +000043#include "PluginDocument.h"
eric@webkit.orge37f5952010-06-28 07:56:10 +000044#include "RawDataDocumentParser.h"
weinig@apple.com123e4aa2013-04-14 00:54:27 +000045#include "ScriptController.h"
eric@webkit.orge37f5952010-06-28 07:56:10 +000046#include "ScriptableDocumentParser.h"
abarth@webkit.org412c54e2010-04-20 22:12:16 +000047#include "SecurityOrigin.h"
andersca@apple.coma57d5552014-12-22 23:42:30 +000048#include "SecurityOriginPolicy.h"
abarth@webkit.org412c54e2010-04-20 22:12:16 +000049#include "SegmentedString.h"
50#include "Settings.h"
beidson@apple.com34f94512010-05-18 23:53:31 +000051#include "SinkDocument.h"
abarth@webkit.org412c54e2010-04-20 22:12:16 +000052#include "TextResourceDecoder.h"
akling@apple.comf8515982013-09-02 18:50:01 +000053#include <wtf/Ref.h>
eric@webkit.orge37f5952010-06-28 07:56:10 +000054
abarth@webkit.org412c54e2010-04-20 22:12:16 +000055namespace WebCore {
56
57static inline bool canReferToParentFrameEncoding(const Frame* frame, const Frame* parentFrame)
58{
akling@apple.com6be0e972017-01-18 19:35:49 +000059 return parentFrame && parentFrame->document()->securityOrigin().canAccess(frame->document()->securityOrigin());
abarth@webkit.org412c54e2010-04-20 22:12:16 +000060}
61
62DocumentWriter::DocumentWriter(Frame* frame)
63 : m_frame(frame)
abarth@webkit.org99edc532011-06-12 00:51:11 +000064 , m_hasReceivedSomeData(false)
abarth@webkit.org412c54e2010-04-20 22:12:16 +000065 , m_encodingWasChosenByUser(false)
commit-queue@webkit.orgfe59ee02012-03-06 22:45:12 +000066 , m_state(NotStartedWritingState)
abarth@webkit.org412c54e2010-04-20 22:12:16 +000067{
68}
69
eric@webkit.org5bfa04d2010-06-24 23:28:05 +000070// This is only called by ScriptController::executeIfJavaScriptURL
71// and always contains the result of evaluating a javascript: url.
72// This is the <iframe src="javascript:'html'"> case.
abarth@webkit.org1a142b72011-10-12 17:05:41 +000073void DocumentWriter::replaceDocument(const String& source, Document* ownerDocument)
abarth@webkit.org412c54e2010-04-20 22:12:16 +000074{
andersca@apple.comdf550b92013-08-15 22:17:17 +000075 m_frame->loader().stopAllLoaders();
bfulgham@apple.come8151232016-12-23 00:20:27 +000076
77 // If we are in the midst of changing the frame's document, don't execute script
mcatanzaro@igalia.com458380d2017-02-09 13:57:45 +000078 // that modifies the document further:
bfulgham@apple.come8151232016-12-23 00:20:27 +000079 if (m_frame->documentIsBeingReplaced())
80 return;
81
abarth@webkit.org1a142b72011-10-12 17:05:41 +000082 begin(m_frame->document()->url(), true, ownerDocument);
eric@webkit.org5bfa04d2010-06-24 23:28:05 +000083
jiewen_tan@apple.com55336222015-12-02 19:04:07 +000084 // begin() might fire an unload event, which will result in a situation where no new document has been attached,
85 // and the old document has been detached. Therefore, bail out if no document is attached.
86 if (!m_frame->document())
87 return;
88
eric@webkit.orgd80f85e2010-06-24 23:41:25 +000089 if (!source.isNull()) {
abarth@webkit.org99edc532011-06-12 00:51:11 +000090 if (!m_hasReceivedSomeData) {
91 m_hasReceivedSomeData = true;
benjamin@webkit.org6d7ab062014-05-30 00:15:18 +000092 m_frame->document()->setCompatibilityMode(DocumentCompatibilityMode::NoQuirksMode);
eric@webkit.org5bfa04d2010-06-24 23:28:05 +000093 }
eric@webkit.org71d0f462010-06-25 07:09:36 +000094
eric@webkit.org44a233c2010-06-25 23:14:00 +000095 // FIXME: This should call DocumentParser::appendBytes instead of append
96 // to support RawDataDocumentParsers.
andersca@apple.com7256f672014-01-18 17:11:46 +000097 if (DocumentParser* parser = m_frame->document()->parser())
eric@webkit.org068ee692013-03-01 21:53:26 +000098 parser->append(source.impl());
eric@webkit.org5bfa04d2010-06-24 23:28:05 +000099 }
100
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000101 end();
102}
103
104void DocumentWriter::clear()
105{
cdumez@apple.comd839ea12015-07-04 19:42:18 +0000106 m_decoder = nullptr;
abarth@webkit.org99edc532011-06-12 00:51:11 +0000107 m_hasReceivedSomeData = false;
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000108 if (!m_encodingWasChosenByUser)
109 m_encoding = String();
110}
111
112void DocumentWriter::begin()
113{
darin@apple.com5ffbb5c2013-09-27 16:39:41 +0000114 begin(URL());
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000115}
116
akling@apple.comf3266b92015-08-09 08:11:32 +0000117Ref<Document> DocumentWriter::createDocument(const URL& url)
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000118{
akling@apple.com63e53cb2014-02-05 20:42:37 +0000119 if (!m_frame->loader().stateMachine().isDisplayingInitialEmptyDocument() && m_frame->loader().client().shouldAlwaysUsePluginDocument(m_mimeType))
japhet@chromium.org6a088ce2010-06-25 17:17:45 +0000120 return PluginDocument::create(m_frame, url);
dbates@webkit.org46a1c6f2013-12-19 18:10:07 +0000121#if PLATFORM(IOS)
timothy_horton@apple.com12105542014-06-18 01:35:32 +0000122 if (MIMETypeRegistry::isPDFMIMEType(m_mimeType) && (m_frame->isMainFrame() || !m_frame->settings().useImageDocumentForSubframePDF()))
timothy_horton@apple.com83109922014-08-31 22:01:34 +0000123 return SinkDocument::create(m_frame, url);
dbates@webkit.org46a1c6f2013-12-19 18:10:07 +0000124#endif
akling@apple.com7f50aae2013-08-22 16:01:31 +0000125 if (!m_frame->loader().client().hasHTMLView())
antti@apple.come9bd3262014-01-02 15:50:28 +0000126 return Document::createNonRenderedPlaceholder(m_frame, url);
andersca@apple.com003f4662014-02-17 23:53:29 +0000127 return DOMImplementation::createDocument(m_mimeType, m_frame, url);
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000128}
129
darin@apple.com5ffbb5c2013-09-27 16:39:41 +0000130void DocumentWriter::begin(const URL& urlReference, bool dispatch, Document* ownerDocument)
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000131{
abarth@webkit.org0cb1dfc2011-08-30 21:31:57 +0000132 // We grab a local copy of the URL because it's easy for callers to supply
133 // a URL that will be deallocated during the execution of this function.
134 // For example, see <https://bugs.webkit.org/show_bug.cgi?id=66360>.
darin@apple.com5ffbb5c2013-09-27 16:39:41 +0000135 URL url = urlReference;
abarth@webkit.org0cb1dfc2011-08-30 21:31:57 +0000136
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000137 // Create a new document before clearing the frame, because it may need to
138 // inherit an aliased security context.
akling@apple.comf3266b92015-08-09 08:11:32 +0000139 Ref<Document> document = createDocument(url);
beidson@apple.com34f94512010-05-18 23:53:31 +0000140
141 // If the new document is for a Plugin but we're supposed to be sandboxed from Plugins,
abarth@webkit.org5d72ad22010-06-14 04:40:20 +0000142 // then replace the document with one whose parser will ignore the incoming data (bug 39323)
abarth@webkit.org29f0c1a2011-11-05 01:32:07 +0000143 if (document->isPluginDocument() && document->isSandboxed(SandboxPlugins))
japhet@chromium.org6a088ce2010-06-25 17:17:45 +0000144 document = SinkDocument::create(m_frame, url);
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000145
abarth@webkit.org15f9e212011-04-07 04:43:50 +0000146 // FIXME: Do we need to consult the content security policy here about blocked plug-ins?
147
akling@apple.com63e53cb2014-02-05 20:42:37 +0000148 bool shouldReuseDefaultView = m_frame->loader().stateMachine().isDisplayingInitialEmptyDocument() && m_frame->document()->isSecureTransitionTo(url);
abarth@webkit.org23ea90a2012-08-14 19:47:59 +0000149 if (shouldReuseDefaultView)
150 document->takeDOMWindowFrom(m_frame->document());
151 else
152 document->createDOMWindow();
153
bfulgham@apple.comb30d7f82016-06-07 15:47:30 +0000154 // Per <http://www.w3.org/TR/upgrade-insecure-requests/>, we need to retain an ongoing set of upgraded
155 // requests in new navigation contexts. Although this information is present when we construct the
156 // Document object, it is discard in the subsequent 'clear' statements below. So, we must capture it
157 // so we can restore it.
158 HashSet<RefPtr<SecurityOrigin>> insecureNavigationRequestsToUpgrade;
bfulgham@apple.com01c956f2016-08-16 20:32:57 +0000159 if (auto* existingDocument = m_frame->document())
bfulgham@apple.comb30d7f82016-06-07 15:47:30 +0000160 insecureNavigationRequestsToUpgrade = existingDocument->contentSecurityPolicy()->takeNavigationRequestsToUpgrade();
bfulgham@apple.comb30d7f82016-06-07 15:47:30 +0000161
akling@apple.comf3266b92015-08-09 08:11:32 +0000162 m_frame->loader().clear(document.ptr(), !shouldReuseDefaultView, !shouldReuseDefaultView);
japhet@chromium.orgaf889b92011-02-11 17:28:06 +0000163 clear();
abarth@webkit.org23ea90a2012-08-14 19:47:59 +0000164
jiewen_tan@apple.com55336222015-12-02 19:04:07 +0000165 // m_frame->loader().clear() might fire unload event which could remove the view of the document.
166 // Bail out if document has no view.
167 if (!document->view())
168 return;
169
abarth@webkit.org23ea90a2012-08-14 19:47:59 +0000170 if (!shouldReuseDefaultView)
psolanki@apple.comc5b5dad2013-08-16 17:55:32 +0000171 m_frame->script().updatePlatformScriptObjects();
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000172
andersca@apple.comdf550b92013-08-15 22:17:17 +0000173 m_frame->loader().setOutgoingReferrer(url);
akling@apple.com6fbca0f2014-12-17 19:39:16 +0000174 m_frame->setDocument(document.copyRef());
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000175
bfulgham@apple.comb30d7f82016-06-07 15:47:30 +0000176 document->contentSecurityPolicy()->setInsecureNavigationRequestsToUpgrade(WTFMove(insecureNavigationRequestsToUpgrade));
177
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000178 if (m_decoder)
179 document->setDecoder(m_decoder.get());
abarth@webkit.org1a142b72011-10-12 17:05:41 +0000180 if (ownerDocument) {
181 document->setCookieURL(ownerDocument->cookieURL());
andersca@apple.coma57d5552014-12-22 23:42:30 +0000182 document->setSecurityOriginPolicy(ownerDocument->securityOriginPolicy());
dbates@webkit.org2abec1b2016-12-08 23:54:13 +0000183 document->setStrictMixedContentMode(ownerDocument->isStrictMixedContentMode());
commit-queue@webkit.org9416cdd2011-09-28 21:01:37 +0000184 }
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000185
andersca@apple.comdf550b92013-08-15 22:17:17 +0000186 m_frame->loader().didBeginDocument(dispatch);
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000187
188 document->implicitOpen();
189
abarth@webkit.org99edc532011-06-12 00:51:11 +0000190 // We grab a reference to the parser so that we'll always send data to the
191 // original parser, even if the document acquires a new parser (e.g., via
192 // document.open).
abarth@webkit.org14a3bdf2011-06-11 00:56:13 +0000193 m_parser = document->parser();
194
akling@apple.com7f50aae2013-08-22 16:01:31 +0000195 if (m_frame->view() && m_frame->loader().client().hasHTMLView())
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000196 m_frame->view()->setContentsSize(IntSize());
commit-queue@webkit.orgfe59ee02012-03-06 22:45:12 +0000197
198 m_state = StartedWritingState;
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000199}
200
eric@webkit.org44a233c2010-06-25 23:14:00 +0000201TextResourceDecoder* DocumentWriter::createDecoderIfNeeded()
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000202{
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000203 if (!m_decoder) {
akling@apple.com17523502013-08-17 10:58:40 +0000204 m_decoder = TextResourceDecoder::create(m_mimeType,
205 m_frame->settings().defaultTextEncodingName(),
206 m_frame->settings().usesEncodingDetector());
darin@apple.comfed4d162013-08-25 02:28:06 +0000207 Frame* parentFrame = m_frame->tree().parent();
akling@apple.com17523502013-08-17 10:58:40 +0000208 // Set the hint encoding to the parent frame encoding only if
209 // the parent and the current frames share the security origin.
210 // We impose this condition because somebody can make a child frame
211 // containing a carefully crafted html/javascript in one encoding
212 // that can be mistaken for hintEncoding (or related encoding) by
213 // an auto detector. When interpreted in the latter, it could be
214 // an attack vector.
215 // FIXME: This might be too cautious for non-7bit-encodings and
216 // we may consider relaxing this later after testing.
217 if (canReferToParentFrameEncoding(m_frame, parentFrame))
218 m_decoder->setHintEncoding(parentFrame->document()->decoder());
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000219 if (m_encoding.isEmpty()) {
220 if (canReferToParentFrameEncoding(m_frame, parentFrame))
dewei_zhu@apple.com5e4916c2015-09-15 02:13:03 +0000221 m_decoder->setEncoding(parentFrame->document()->textEncoding(), TextResourceDecoder::EncodingFromParentFrame);
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000222 } else {
223 m_decoder->setEncoding(m_encoding,
224 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
225 }
226 m_frame->document()->setDecoder(m_decoder.get());
227 }
eric@webkit.org44a233c2010-06-25 23:14:00 +0000228 return m_decoder.get();
229}
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000230
hyatt@apple.comce8ee2a2010-08-27 20:29:34 +0000231void DocumentWriter::reportDataReceived()
eric@webkit.org44a233c2010-06-25 23:14:00 +0000232{
233 ASSERT(m_decoder);
abarth@webkit.org99edc532011-06-12 00:51:11 +0000234 if (m_hasReceivedSomeData)
235 return;
236 m_hasReceivedSomeData = true;
237 if (m_decoder->encoding().usesVisualOrdering())
238 m_frame->document()->setVisuallyOrdered();
antti@apple.com0eb87242017-03-02 06:19:04 +0000239 m_frame->document()->resolveStyle(Document::ResolveStyleType::Rebuild);
eric@webkit.org44a233c2010-06-25 23:14:00 +0000240}
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000241
abarth@webkit.org031254e2011-06-12 04:19:39 +0000242void DocumentWriter::addData(const char* bytes, size_t length)
eric@webkit.org44a233c2010-06-25 23:14:00 +0000243{
commit-queue@webkit.orgfe59ee02012-03-06 22:45:12 +0000244 // Check that we're inside begin()/end().
245 // FIXME: Change these to ASSERT once https://bugs.webkit.org/show_bug.cgi?id=80427 has
246 // been resolved.
247 if (m_state == NotStartedWritingState)
248 CRASH();
249 if (m_state == FinishedWritingState)
250 CRASH();
251
252 ASSERT(m_parser);
weinig@apple.comee87b2f2013-10-05 23:59:58 +0000253 m_parser->appendBytes(*this, bytes, length);
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000254}
255
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000256void DocumentWriter::end()
257{
japhet@chromium.org440e4fd2012-04-13 01:07:27 +0000258 ASSERT(m_frame->page());
259 ASSERT(m_frame->document());
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000260
commit-queue@webkit.orgfe59ee02012-03-06 22:45:12 +0000261 // The parser is guaranteed to be released after this point. begin() would
262 // have to be called again before we can start writing more data.
263 m_state = FinishedWritingState;
264
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000265 // http://bugs.webkit.org/show_bug.cgi?id=10854
266 // The frame's last ref may be removed and it can be deleted by checkCompleted(),
267 // so we'll add a protective refcount
akling@apple.comf8515982013-09-02 18:50:01 +0000268 Ref<Frame> protect(*m_frame);
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000269
abarth@webkit.org5b4ba322011-08-03 18:56:37 +0000270 if (!m_parser)
271 return;
abarth@webkit.org99edc532011-06-12 00:51:11 +0000272 // FIXME: m_parser->finish() should imply m_parser->flush().
weinig@apple.comee87b2f2013-10-05 23:59:58 +0000273 m_parser->flush(*this);
abarth@webkit.org14a3bdf2011-06-11 00:56:13 +0000274 if (!m_parser)
275 return;
276 m_parser->finish();
cdumez@apple.comd839ea12015-07-04 19:42:18 +0000277 m_parser = nullptr;
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000278}
279
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000280void DocumentWriter::setEncoding(const String& name, bool userChosen)
281{
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000282 m_encoding = name;
283 m_encodingWasChosenByUser = userChosen;
284}
285
ap@apple.com048c67f2010-10-04 19:48:49 +0000286void DocumentWriter::setDocumentWasLoadedAsPartOfNavigation()
287{
commit-queue@webkit.orgfe59ee02012-03-06 22:45:12 +0000288 ASSERT(m_parser && !m_parser->isStopped());
abarth@webkit.org14a3bdf2011-06-11 00:56:13 +0000289 m_parser->setDocumentWasLoadedAsPartOfNavigation();
ap@apple.com048c67f2010-10-04 19:48:49 +0000290}
291
abarth@webkit.org412c54e2010-04-20 22:12:16 +0000292} // namespace WebCore