Home | History | Annotate | Download | only in imports
      1 /*
      2  * Copyright (C) 2013 Google Inc. 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 are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "core/html/imports/HTMLImportLoader.h"
     33 
     34 #include "core/dom/Document.h"
     35 #include "core/dom/StyleEngine.h"
     36 #include "core/dom/custom/CustomElementSyncMicrotaskQueue.h"
     37 #include "core/html/HTMLDocument.h"
     38 #include "core/html/imports/HTMLImportChild.h"
     39 #include "core/html/imports/HTMLImportsController.h"
     40 #include "core/loader/DocumentWriter.h"
     41 #include "platform/network/ContentSecurityPolicyResponseHeaders.h"
     42 
     43 
     44 namespace WebCore {
     45 
     46 HTMLImportLoader::HTMLImportLoader(HTMLImportsController* controller)
     47     : m_controller(controller)
     48     , m_state(StateLoading)
     49     , m_microtaskQueue(CustomElementSyncMicrotaskQueue::create())
     50 {
     51 }
     52 
     53 HTMLImportLoader::~HTMLImportLoader()
     54 {
     55 #if !ENABLE(OILPAN)
     56     clear();
     57 #endif
     58 }
     59 
     60 #if !ENABLE(OILPAN)
     61 void HTMLImportLoader::importDestroyed()
     62 {
     63     clear();
     64 }
     65 
     66 void HTMLImportLoader::clear()
     67 {
     68     m_controller = nullptr;
     69     if (m_document) {
     70         m_document->setImportsController(0);
     71         m_document->cancelParsing();
     72         m_document.clear();
     73     }
     74 }
     75 #endif
     76 
     77 void HTMLImportLoader::startLoading(const ResourcePtr<RawResource>& resource)
     78 {
     79     setResource(resource);
     80 }
     81 
     82 void HTMLImportLoader::responseReceived(Resource* resource, const ResourceResponse& response)
     83 {
     84     // Resource may already have been loaded with the import loader
     85     // being added as a client later & now being notified. Fail early.
     86     if (resource->loadFailedOrCanceled() || response.httpStatusCode() >= 400) {
     87         setState(StateError);
     88         return;
     89     }
     90     setState(startWritingAndParsing(response));
     91 }
     92 
     93 void HTMLImportLoader::dataReceived(Resource*, const char* data, int length)
     94 {
     95     RefPtrWillBeRawPtr<DocumentWriter> protectingWriter(m_writer.get());
     96     m_writer->addData(data, length);
     97 }
     98 
     99 void HTMLImportLoader::notifyFinished(Resource* resource)
    100 {
    101     // The writer instance indicates that a part of the document can be already loaded.
    102     // We don't take such a case as an error because the partially-loaded document has been visible from script at this point.
    103     if (resource->loadFailedOrCanceled() && !m_writer) {
    104         setState(StateError);
    105         return;
    106     }
    107 
    108     setState(finishWriting());
    109 }
    110 
    111 HTMLImportLoader::State HTMLImportLoader::startWritingAndParsing(const ResourceResponse& response)
    112 {
    113     ASSERT(!m_imports.isEmpty());
    114     DocumentInit init = DocumentInit(response.url(), 0, m_controller->master()->contextDocument(), m_controller)
    115         .withRegistrationContext(m_controller->master()->registrationContext());
    116     m_document = HTMLDocument::create(init);
    117     m_writer = DocumentWriter::create(m_document.get(), response.mimeType(), "UTF-8");
    118 
    119     return StateLoading;
    120 }
    121 
    122 HTMLImportLoader::State HTMLImportLoader::finishWriting()
    123 {
    124     return StateWritten;
    125 }
    126 
    127 HTMLImportLoader::State HTMLImportLoader::finishParsing()
    128 {
    129     return StateParsed;
    130 }
    131 
    132 HTMLImportLoader::State HTMLImportLoader::finishLoading()
    133 {
    134     return StateLoaded;
    135 }
    136 
    137 void HTMLImportLoader::setState(State state)
    138 {
    139     if (m_state == state)
    140         return;
    141 
    142     m_state = state;
    143 
    144     if (m_state == StateParsed || m_state == StateError || m_state == StateWritten) {
    145         if (RefPtrWillBeRawPtr<DocumentWriter> writer = m_writer.release())
    146             writer->end();
    147     }
    148 
    149     // Since DocumentWriter::end() can let setState() reenter, we shouldn't refer to m_state here.
    150     if (state == StateLoaded || state == StateError)
    151         didFinishLoading();
    152 }
    153 
    154 void HTMLImportLoader::didFinishParsing()
    155 {
    156     setState(finishParsing());
    157     if (!hasPendingResources())
    158         setState(finishLoading());
    159 }
    160 
    161 void HTMLImportLoader::didRemoveAllPendingStylesheet()
    162 {
    163     if (m_state == StateParsed)
    164         setState(finishLoading());
    165 }
    166 
    167 bool HTMLImportLoader::hasPendingResources() const
    168 {
    169     return m_document && m_document->styleEngine()->hasPendingSheets();
    170 }
    171 
    172 void HTMLImportLoader::didFinishLoading()
    173 {
    174     for (size_t i = 0; i < m_imports.size(); ++i)
    175         m_imports[i]->didFinishLoading();
    176 
    177     clearResource();
    178 
    179     ASSERT(!m_document || !m_document->parsing());
    180 }
    181 
    182 void HTMLImportLoader::moveToFirst(HTMLImportChild* import)
    183 {
    184     size_t position = m_imports.find(import);
    185     ASSERT(kNotFound != position);
    186     m_imports.remove(position);
    187     m_imports.insert(0, import);
    188 }
    189 
    190 void HTMLImportLoader::addImport(HTMLImportChild* import)
    191 {
    192     ASSERT(kNotFound == m_imports.find(import));
    193 
    194     m_imports.append(import);
    195     import->normalize();
    196     if (isDone())
    197         import->didFinishLoading();
    198 }
    199 
    200 #if !ENABLE(OILPAN)
    201 void HTMLImportLoader::removeImport(HTMLImportChild* client)
    202 {
    203     ASSERT(kNotFound != m_imports.find(client));
    204     m_imports.remove(m_imports.find(client));
    205 }
    206 #endif
    207 
    208 bool HTMLImportLoader::shouldBlockScriptExecution() const
    209 {
    210     return firstImport()->state().shouldBlockScriptExecution();
    211 }
    212 
    213 PassRefPtrWillBeRawPtr<CustomElementSyncMicrotaskQueue> HTMLImportLoader::microtaskQueue() const
    214 {
    215     return m_microtaskQueue;
    216 }
    217 
    218 void HTMLImportLoader::trace(Visitor* visitor)
    219 {
    220     visitor->trace(m_controller);
    221 #if ENABLE(OILPAN)
    222     visitor->trace(m_imports);
    223 #endif
    224     visitor->trace(m_document);
    225     visitor->trace(m_writer);
    226     visitor->trace(m_microtaskQueue);
    227 }
    228 
    229 } // namespace WebCore
    230