Home | History | Annotate | Download | only in loader
      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