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_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. 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 87 void DocumentWriter::clear() 88 { 89 m_decoder = 0; 90 m_receivedData = false; 91 if (!m_encodingWasChosenByUser) 92 m_encoding = String(); 93 } 94 95 void DocumentWriter::begin() 96 { 97 begin(KURL()); 98 } 99 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 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 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 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 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 210 void DocumentWriter::end() 211 { 212 m_frame->loader()->didEndDocument(); 213 endIfNotLoadingMainResource(); 214 } 215 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 231 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 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 248 void DocumentWriter::setDecoder(TextResourceDecoder* decoder) 249 { 250 m_decoder = decoder; 251 } 252 253 String DocumentWriter::deprecatedFrameEncoding() const 254 { 255 return m_frame->document()->url().isEmpty() ? m_encoding : encoding(); 256 } 257 258 void DocumentWriter::setDocumentWasLoadedAsPartOfNavigation() 259 { 260 m_frame->document()->parser()->setDocumentWasLoadedAsPartOfNavigation(); 261 } 262 263 } // namespace WebCore 264