Store Ad Click Attribution requests in the network process
[WebKit-https.git] / Source / WebCore / loader / DocumentWriter.cpp
1 /*
2  * Copyright (C) 2010. Adam Barth. All rights reserved.
3  * Copyright (C) 2016 Apple Inc. All rights reserved.
4  *
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. 
14  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
15  *     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
33 #include "ContentSecurityPolicy.h"
34 #include "DOMImplementation.h"
35 #include "DOMWindow.h"
36 #include "Frame.h"
37 #include "FrameLoader.h"
38 #include "FrameLoaderClient.h"
39 #include "FrameLoaderStateMachine.h"
40 #include "FrameView.h"
41 #include "MIMETypeRegistry.h"
42 #include "PluginDocument.h"
43 #include "RawDataDocumentParser.h"
44 #include "ScriptController.h"
45 #include "ScriptableDocumentParser.h"
46 #include "SecurityOrigin.h"
47 #include "SecurityOriginPolicy.h"
48 #include "SegmentedString.h"
49 #include "Settings.h"
50 #include "SinkDocument.h"
51 #include "TextResourceDecoder.h"
52 #include <wtf/Ref.h>
53
54 namespace WebCore {
55
56 static inline bool canReferToParentFrameEncoding(const Frame* frame, const Frame* parentFrame) 
57 {
58     return parentFrame && parentFrame->document()->securityOrigin().canAccess(frame->document()->securityOrigin());
59 }
60     
61 DocumentWriter::DocumentWriter(Frame* frame)
62     : m_frame(frame)
63     , m_hasReceivedSomeData(false)
64     , m_encodingWasChosenByUser(false)
65     , m_state(NotStartedWritingState)
66 {
67 }
68
69 // This is only called by ScriptController::executeIfJavaScriptURL
70 // and always contains the result of evaluating a javascript: url.
71 // This is the <iframe src="javascript:'html'"> case.
72 void DocumentWriter::replaceDocument(const String& source, Document* ownerDocument)
73 {
74     m_frame->loader().stopAllLoaders();
75
76     // If we are in the midst of changing the frame's document, don't execute script
77     // that modifies the document further:
78     if (m_frame->documentIsBeingReplaced())
79         return;
80
81     begin(m_frame->document()->url(), true, ownerDocument);
82
83     // begin() might fire an unload event, which will result in a situation where no new document has been attached,
84     // and the old document has been detached. Therefore, bail out if no document is attached.
85     if (!m_frame->document())
86         return;
87
88     if (!source.isNull()) {
89         if (!m_hasReceivedSomeData) {
90             m_hasReceivedSomeData = true;
91             m_frame->document()->setCompatibilityMode(DocumentCompatibilityMode::NoQuirksMode);
92         }
93
94         // FIXME: This should call DocumentParser::appendBytes instead of append
95         // to support RawDataDocumentParsers.
96         if (DocumentParser* parser = m_frame->document()->parser())
97             parser->append(source.impl());
98     }
99
100     end();
101 }
102
103 void DocumentWriter::clear()
104 {
105     m_decoder = nullptr;
106     m_hasReceivedSomeData = false;
107     if (!m_encodingWasChosenByUser)
108         m_encoding = String();
109 }
110
111 bool DocumentWriter::begin()
112 {
113     return begin(URL());
114 }
115
116 Ref<Document> DocumentWriter::createDocument(const URL& url)
117 {
118     if (!m_frame->loader().stateMachine().isDisplayingInitialEmptyDocument() && m_frame->loader().client().shouldAlwaysUsePluginDocument(m_mimeType))
119         return PluginDocument::create(m_frame, url);
120 #if PLATFORM(IOS_FAMILY)
121     if (MIMETypeRegistry::isPDFMIMEType(m_mimeType) && (m_frame->isMainFrame() || !m_frame->settings().useImageDocumentForSubframePDF()))
122         return SinkDocument::create(m_frame, url);
123 #endif
124     if (!m_frame->loader().client().hasHTMLView())
125         return Document::createNonRenderedPlaceholder(m_frame, url);
126     return DOMImplementation::createDocument(m_mimeType, m_frame, url);
127 }
128
129 bool DocumentWriter::begin(const URL& urlReference, bool dispatch, Document* ownerDocument)
130 {
131     // We grab a local copy of the URL because it's easy for callers to supply
132     // a URL that will be deallocated during the execution of this function.
133     // For example, see <https://bugs.webkit.org/show_bug.cgi?id=66360>.
134     URL url = urlReference;
135
136     // Create a new document before clearing the frame, because it may need to
137     // inherit an aliased security context.
138     Ref<Document> document = createDocument(url);
139     
140     // If the new document is for a Plugin but we're supposed to be sandboxed from Plugins,
141     // then replace the document with one whose parser will ignore the incoming data (bug 39323)
142     if (document->isPluginDocument() && document->isSandboxed(SandboxPlugins))
143         document = SinkDocument::create(m_frame, url);
144
145     // FIXME: Do we need to consult the content security policy here about blocked plug-ins?
146
147     bool shouldReuseDefaultView = m_frame->loader().stateMachine().isDisplayingInitialEmptyDocument() && m_frame->document()->isSecureTransitionTo(url);
148     if (shouldReuseDefaultView)
149         document->takeDOMWindowFrom(*m_frame->document());
150     else
151         document->createDOMWindow();
152
153     // Per <http://www.w3.org/TR/upgrade-insecure-requests/>, we need to retain an ongoing set of upgraded
154     // requests in new navigation contexts. Although this information is present when we construct the
155     // Document object, it is discard in the subsequent 'clear' statements below. So, we must capture it
156     // so we can restore it.
157     HashSet<SecurityOriginData> insecureNavigationRequestsToUpgrade;
158     if (auto* existingDocument = m_frame->document())
159         insecureNavigationRequestsToUpgrade = existingDocument->contentSecurityPolicy()->takeNavigationRequestsToUpgrade();
160     
161     m_frame->loader().clear(document.ptr(), !shouldReuseDefaultView, !shouldReuseDefaultView);
162     clear();
163
164     // m_frame->loader().clear() might fire unload event which could remove the view of the document.
165     // Bail out if document has no view.
166     if (!document->view())
167         return false;
168
169     if (!shouldReuseDefaultView)
170         m_frame->script().updatePlatformScriptObjects();
171
172     m_frame->loader().setOutgoingReferrer(url);
173     m_frame->setDocument(document.copyRef());
174
175     document->contentSecurityPolicy()->setInsecureNavigationRequestsToUpgrade(WTFMove(insecureNavigationRequestsToUpgrade));
176
177     if (m_decoder)
178         document->setDecoder(m_decoder.get());
179     if (ownerDocument) {
180         document->setCookieURL(ownerDocument->cookieURL());
181         document->setSecurityOriginPolicy(ownerDocument->securityOriginPolicy());
182         document->setStrictMixedContentMode(ownerDocument->isStrictMixedContentMode());
183     }
184
185     m_frame->loader().didBeginDocument(dispatch);
186
187     document->implicitOpen();
188
189     // We grab a reference to the parser so that we'll always send data to the
190     // original parser, even if the document acquires a new parser (e.g., via
191     // document.open).
192     m_parser = document->parser();
193
194     if (m_frame->view() && m_frame->loader().client().hasHTMLView())
195         m_frame->view()->setContentsSize(IntSize());
196
197     m_state = StartedWritingState;
198     return true;
199 }
200
201 TextResourceDecoder* DocumentWriter::createDecoderIfNeeded()
202 {
203     if (!m_decoder) {
204         m_decoder = TextResourceDecoder::create(m_mimeType,
205             m_frame->settings().defaultTextEncodingName(),
206             m_frame->settings().usesEncodingDetector());
207         Frame* parentFrame = m_frame->tree().parent();
208         // 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());
219         if (m_encoding.isEmpty()) {
220             if (canReferToParentFrameEncoding(m_frame, parentFrame))
221                 m_decoder->setEncoding(parentFrame->document()->textEncoding(), TextResourceDecoder::EncodingFromParentFrame);
222         } else {
223             m_decoder->setEncoding(m_encoding,
224                 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
225         }
226         m_frame->document()->setDecoder(m_decoder.get());
227     }
228     return m_decoder.get();
229 }
230
231 void DocumentWriter::reportDataReceived()
232 {
233     ASSERT(m_decoder);
234     if (m_hasReceivedSomeData)
235         return;
236     m_hasReceivedSomeData = true;
237     if (m_decoder->encoding().usesVisualOrdering())
238         m_frame->document()->setVisuallyOrdered();
239     m_frame->document()->resolveStyle(Document::ResolveStyleType::Rebuild);
240 }
241
242 void DocumentWriter::addData(const char* bytes, size_t length)
243 {
244     // 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);
253     m_parser->appendBytes(*this, bytes, length);
254 }
255
256 void DocumentWriter::insertDataSynchronously(const String& markup)
257 {
258     ASSERT(m_state != NotStartedWritingState);
259     ASSERT(m_state != FinishedWritingState);
260     ASSERT(m_parser);
261     m_parser->insert(markup);
262 }
263
264 void DocumentWriter::end()
265 {
266     ASSERT(m_frame->page());
267     ASSERT(m_frame->document());
268
269     // The parser is guaranteed to be released after this point. begin() would
270     // have to be called again before we can start writing more data.
271     m_state = FinishedWritingState;
272
273     // http://bugs.webkit.org/show_bug.cgi?id=10854
274     // The frame's last ref may be removed and it can be deleted by checkCompleted(), 
275     // so we'll add a protective refcount
276     Ref<Frame> protect(*m_frame);
277
278     if (!m_parser)
279         return;
280     // FIXME: m_parser->finish() should imply m_parser->flush().
281     m_parser->flush(*this);
282     if (!m_parser)
283         return;
284     m_parser->finish();
285     m_parser = nullptr;
286 }
287
288 void DocumentWriter::setEncoding(const String& name, bool userChosen)
289 {
290     m_encoding = name;
291     m_encodingWasChosenByUser = userChosen;
292 }
293
294 void DocumentWriter::setDocumentWasLoadedAsPartOfNavigation()
295 {
296     ASSERT(m_parser && !m_parser->isStopped());
297     m_parser->setDocumentWasLoadedAsPartOfNavigation();
298 }
299
300 } // namespace WebCore