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/DocumentParser.h"
     36 #include "core/dom/StyleEngine.h"
     37 #include "core/dom/custom/CustomElementSyncMicrotaskQueue.h"
     38 #include "core/html/HTMLDocument.h"
     39 #include "core/html/imports/HTMLImportChild.h"
     40 #include "core/html/imports/HTMLImportsController.h"
     41 #include "core/loader/DocumentWriter.h"
     42 #include "platform/network/ContentSecurityPolicyResponseHeaders.h"
     43 
     44 
     45 namespace blink {
     46 
     47 HTMLImportLoader::HTMLImportLoader(HTMLImportsController* controller)
     48     : m_controller(controller)
     49     , m_state(StateLoading)
     50     , m_microtaskQueue(CustomElementSyncMicrotaskQueue::create())
     51 {
     52 }
     53 
     54 HTMLImportLoader::~HTMLImportLoader()
     55 {
     56 #if !ENABLE(OILPAN)
     57     clear();
     58 #endif
     59 }
     60 
     61 #if !ENABLE(OILPAN)
     62 void HTMLImportLoader::importDestroyed()
     63 {
     64     clear();
     65 }
     66 
     67 void HTMLImportLoader::clear()
     68 {
     69     m_controller = nullptr;
     70     if (m_document) {
     71         m_document->setImportsController(0);
     72         m_document->cancelParsing();
     73         m_document.clear();
     74     }
     75 }
     76 #endif
     77 
     78 void HTMLImportLoader::startLoading(const ResourcePtr<RawResource>& resource)
     79 {
     80     setResource(resource);
     81 }
     82 
     83 void HTMLImportLoader::responseReceived(Resource* resource, const ResourceResponse& response)
     84 {
     85     // Resource may already have been loaded with the import loader
     86     // being added as a client later & now being notified. Fail early.
     87     if (resource->loadFailedOrCanceled() || response.httpStatusCode() >= 400) {
     88         setState(StateError);
     89         return;
     90     }
     91     setState(startWritingAndParsing(response));
     92 }
     93 
     94 void HTMLImportLoader::dataReceived(Resource*, const char* data, int length)
     95 {
     96     RefPtrWillBeRawPtr<DocumentWriter> protectingWriter(m_writer.get());
     97     m_writer->addData(data, length);
     98 }
     99 
    100 void HTMLImportLoader::notifyFinished(Resource* resource)
    101 {
    102     // The writer instance indicates that a part of the document can be already loaded.
    103     // We don't take such a case as an error because the partially-loaded document has been visible from script at this point.
    104     if (resource->loadFailedOrCanceled() && !m_writer) {
    105         setState(StateError);
    106         return;
    107     }
    108 
    109     setState(finishWriting());
    110 }
    111 
    112 HTMLImportLoader::State HTMLImportLoader::startWritingAndParsing(const ResourceResponse& response)
    113 {
    114     ASSERT(!m_imports.isEmpty());
    115     DocumentInit init = DocumentInit(response.url(), 0, m_controller->master()->contextDocument(), m_controller)
    116         .withRegistrationContext(m_controller->master()->registrationContext());
    117     m_document = HTMLDocument::create(init);
    118     m_writer = DocumentWriter::create(m_document.get(), response.mimeType(), "UTF-8");
    119 
    120     DocumentParser* parser = m_document->parser();
    121     ASSERT(parser);
    122     parser->addClient(this);
    123 
    124     return StateLoading;
    125 }
    126 
    127 HTMLImportLoader::State HTMLImportLoader::finishWriting()
    128 {
    129     return StateWritten;
    130 }
    131 
    132 HTMLImportLoader::State HTMLImportLoader::finishParsing()
    133 {
    134     return StateParsed;
    135 }
    136 
    137 HTMLImportLoader::State HTMLImportLoader::finishLoading()
    138 {
    139     return StateLoaded;
    140 }
    141 
    142 void HTMLImportLoader::setState(State state)
    143 {
    144     if (m_state == state)
    145         return;
    146 
    147     m_state = state;
    148 
    149     if (m_state == StateParsed || m_state == StateError || m_state == StateWritten) {
    150         if (RefPtrWillBeRawPtr<DocumentWriter> writer = m_writer.release())
    151             writer->end();
    152     }
    153 
    154     // Since DocumentWriter::end() can let setState() reenter, we shouldn't refer to m_state here.
    155     if (state == StateLoaded || state == StateError)
    156         didFinishLoading();
    157 }
    158 
    159 void HTMLImportLoader::notifyParserStopped()
    160 {
    161     setState(finishParsing());
    162     if (!hasPendingResources())
    163         setState(finishLoading());
    164 
    165     DocumentParser* parser = m_document->parser();
    166     ASSERT(parser);
    167     parser->removeClient(this);
    168 }
    169 
    170 void HTMLImportLoader::didRemoveAllPendingStylesheet()
    171 {
    172     if (m_state == StateParsed)
    173         setState(finishLoading());
    174 }
    175 
    176 bool HTMLImportLoader::hasPendingResources() const
    177 {
    178     return m_document && m_document->styleEngine()->hasPendingSheets();
    179 }
    180 
    181 void HTMLImportLoader::didFinishLoading()
    182 {
    183     for (size_t i = 0; i < m_imports.size(); ++i)
    184         m_imports[i]->didFinishLoading();
    185 
    186     clearResource();
    187 
    188     ASSERT(!m_document || !m_document->parsing());
    189 }
    190 
    191 void HTMLImportLoader::moveToFirst(HTMLImportChild* import)
    192 {
    193     size_t position = m_imports.find(import);
    194     ASSERT(kNotFound != position);
    195     m_imports.remove(position);
    196     m_imports.insert(0, import);
    197 }
    198 
    199 void HTMLImportLoader::addImport(HTMLImportChild* import)
    200 {
    201     ASSERT(kNotFound == m_imports.find(import));
    202 
    203     m_imports.append(import);
    204     import->normalize();
    205     if (isDone())
    206         import->didFinishLoading();
    207 }
    208 
    209 #if !ENABLE(OILPAN)
    210 void HTMLImportLoader::removeImport(HTMLImportChild* client)
    211 {
    212     ASSERT(kNotFound != m_imports.find(client));
    213     m_imports.remove(m_imports.find(client));
    214 }
    215 #endif
    216 
    217 bool HTMLImportLoader::shouldBlockScriptExecution() const
    218 {
    219     return firstImport()->state().shouldBlockScriptExecution();
    220 }
    221 
    222 PassRefPtrWillBeRawPtr<CustomElementSyncMicrotaskQueue> HTMLImportLoader::microtaskQueue() const
    223 {
    224     return m_microtaskQueue;
    225 }
    226 
    227 void HTMLImportLoader::trace(Visitor* visitor)
    228 {
    229     visitor->trace(m_controller);
    230 #if ENABLE(OILPAN)
    231     visitor->trace(m_imports);
    232 #endif
    233     visitor->trace(m_document);
    234     visitor->trace(m_writer);
    235     visitor->trace(m_microtaskQueue);
    236 }
    237 
    238 } // namespace blink
    239