WebCore/loader/DocumentWriter.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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->loader()->url(), true, m_frame->document()->securityOrigin());
       
    71 
       
    72     if (!source.isNull()) {
       
    73         if (!m_receivedData) {
       
    74             m_receivedData = true;
       
    75             m_frame->document()->setParseMode(Document::Strict);
       
    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     RefPtr<Document> document = createDocument(url);
       
   118     
       
   119     // If the new document is for a Plugin but we're supposed to be sandboxed from Plugins,
       
   120     // then replace the document with one whose parser will ignore the incoming data (bug 39323)
       
   121     if (document->isPluginDocument() && m_frame->loader()->isSandboxed(SandboxPlugins))
       
   122         document = SinkDocument::create(m_frame, url);
       
   123 
       
   124     bool resetScripting = !(m_frame->loader()->stateMachine()->isDisplayingInitialEmptyDocument() && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));
       
   125     m_frame->loader()->clear(resetScripting, resetScripting);
       
   126     if (resetScripting)
       
   127         m_frame->script()->updatePlatformScriptObjects();
       
   128 
       
   129     m_frame->loader()->setURL(url);
       
   130     m_frame->setDocument(document);
       
   131 
       
   132     if (m_decoder)
       
   133         document->setDecoder(m_decoder.get());
       
   134     if (forcedSecurityOrigin)
       
   135         document->setSecurityOrigin(forcedSecurityOrigin.get());
       
   136 
       
   137     m_frame->domWindow()->setURL(document->url());
       
   138     m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
       
   139 
       
   140     m_frame->loader()->didBeginDocument(dispatch);
       
   141 
       
   142     document->implicitOpen();
       
   143 
       
   144     if (m_frame->view() && m_frame->loader()->client()->hasHTMLView())
       
   145         m_frame->view()->setContentsSize(IntSize());
       
   146 }
       
   147 
       
   148 TextResourceDecoder* DocumentWriter::createDecoderIfNeeded()
       
   149 {
       
   150     if (!m_decoder) {
       
   151         if (Settings* settings = m_frame->settings()) {
       
   152             m_decoder = TextResourceDecoder::create(m_mimeType,
       
   153                 settings->defaultTextEncodingName(),
       
   154                 settings->usesEncodingDetector());
       
   155             Frame* parentFrame = m_frame->tree()->parent();
       
   156             // Set the hint encoding to the parent frame encoding only if
       
   157             // the parent and the current frames share the security origin.
       
   158             // We impose this condition because somebody can make a child frame 
       
   159             // containing a carefully crafted html/javascript in one encoding
       
   160             // that can be mistaken for hintEncoding (or related encoding) by
       
   161             // an auto detector. When interpreted in the latter, it could be
       
   162             // an attack vector.
       
   163             // FIXME: This might be too cautious for non-7bit-encodings and
       
   164             // we may consider relaxing this later after testing.
       
   165             if (canReferToParentFrameEncoding(m_frame, parentFrame))
       
   166                 m_decoder->setHintEncoding(parentFrame->document()->decoder());
       
   167         } else
       
   168             m_decoder = TextResourceDecoder::create(m_mimeType, String());
       
   169         Frame* parentFrame = m_frame->tree()->parent();
       
   170         if (m_encoding.isEmpty()) {
       
   171             if (canReferToParentFrameEncoding(m_frame, parentFrame))
       
   172                 m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::EncodingFromParentFrame);
       
   173         } else {
       
   174             m_decoder->setEncoding(m_encoding,
       
   175                 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
       
   176         }
       
   177         m_frame->document()->setDecoder(m_decoder.get());
       
   178     }
       
   179     return m_decoder.get();
       
   180 }
       
   181 
       
   182 void DocumentWriter::reportDataRecieved()
       
   183 {
       
   184     ASSERT(m_decoder);
       
   185     if (!m_receivedData) {
       
   186         m_receivedData = true;
       
   187         if (m_decoder->encoding().usesVisualOrdering())
       
   188             m_frame->document()->setVisuallyOrdered();
       
   189         m_frame->document()->recalcStyle(Node::Force);
       
   190     }
       
   191 }
       
   192 
       
   193 void DocumentWriter::addData(const char* str, int len, bool flush)
       
   194 {
       
   195     if (len == -1)
       
   196         len = strlen(str);
       
   197 
       
   198     DocumentParser* parser = m_frame->document()->parser();
       
   199     if (parser)
       
   200         parser->appendBytes(this, str, len, flush);
       
   201 }
       
   202 
       
   203 void DocumentWriter::end()
       
   204 {
       
   205     m_frame->loader()->didEndDocument();
       
   206     endIfNotLoadingMainResource();
       
   207 }
       
   208 
       
   209 void DocumentWriter::endIfNotLoadingMainResource()
       
   210 {
       
   211     if (m_frame->loader()->isLoadingMainResource() || !m_frame->page() || !m_frame->document())
       
   212         return;
       
   213 
       
   214     // http://bugs.webkit.org/show_bug.cgi?id=10854
       
   215     // The frame's last ref may be removed and it can be deleted by checkCompleted(), 
       
   216     // so we'll add a protective refcount
       
   217     RefPtr<Frame> protector(m_frame);
       
   218 
       
   219     // make sure nothing's left in there
       
   220     addData(0, 0, true);
       
   221     m_frame->document()->finishParsing();
       
   222 }
       
   223 
       
   224 String DocumentWriter::encoding() const
       
   225 {
       
   226     if (m_encodingWasChosenByUser && !m_encoding.isEmpty())
       
   227         return m_encoding;
       
   228     if (m_decoder && m_decoder->encoding().isValid())
       
   229         return m_decoder->encoding().name();
       
   230     Settings* settings = m_frame->settings();
       
   231     return settings ? settings->defaultTextEncodingName() : String();
       
   232 }
       
   233 
       
   234 void DocumentWriter::setEncoding(const String& name, bool userChosen)
       
   235 {
       
   236     m_frame->loader()->willSetEncoding();
       
   237     m_encoding = name;
       
   238     m_encodingWasChosenByUser = userChosen;
       
   239 }
       
   240 
       
   241 void DocumentWriter::setDecoder(TextResourceDecoder* decoder)
       
   242 {
       
   243     m_decoder = decoder;
       
   244 }
       
   245 
       
   246 String DocumentWriter::deprecatedFrameEncoding() const
       
   247 {
       
   248     return m_frame->loader()->url().isEmpty() ? m_encoding : encoding();
       
   249 }
       
   250 
       
   251 } // namespace WebCore