• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
HTMLImportLoader(HTMLImportsController * controller)47 HTMLImportLoader::HTMLImportLoader(HTMLImportsController* controller)
48     : m_controller(controller)
49     , m_state(StateLoading)
50     , m_microtaskQueue(CustomElementSyncMicrotaskQueue::create())
51 {
52 }
53 
~HTMLImportLoader()54 HTMLImportLoader::~HTMLImportLoader()
55 {
56 #if !ENABLE(OILPAN)
57     clear();
58 #endif
59 }
60 
61 #if !ENABLE(OILPAN)
importDestroyed()62 void HTMLImportLoader::importDestroyed()
63 {
64     clear();
65 }
66 
clear()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 
startLoading(const ResourcePtr<RawResource> & resource)78 void HTMLImportLoader::startLoading(const ResourcePtr<RawResource>& resource)
79 {
80     setResource(resource);
81 }
82 
responseReceived(Resource * resource,const ResourceResponse & response)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 
dataReceived(Resource *,const char * data,int length)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 
notifyFinished(Resource * resource)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 
startWritingAndParsing(const ResourceResponse & response)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 
finishWriting()127 HTMLImportLoader::State HTMLImportLoader::finishWriting()
128 {
129     return StateWritten;
130 }
131 
finishParsing()132 HTMLImportLoader::State HTMLImportLoader::finishParsing()
133 {
134     return StateParsed;
135 }
136 
finishLoading()137 HTMLImportLoader::State HTMLImportLoader::finishLoading()
138 {
139     return StateLoaded;
140 }
141 
setState(State state)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 
notifyParserStopped()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 
didRemoveAllPendingStylesheet()170 void HTMLImportLoader::didRemoveAllPendingStylesheet()
171 {
172     if (m_state == StateParsed)
173         setState(finishLoading());
174 }
175 
hasPendingResources() const176 bool HTMLImportLoader::hasPendingResources() const
177 {
178     return m_document && m_document->styleEngine()->hasPendingSheets();
179 }
180 
didFinishLoading()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 
moveToFirst(HTMLImportChild * import)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 
addImport(HTMLImportChild * import)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)
removeImport(HTMLImportChild * client)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 
shouldBlockScriptExecution() const217 bool HTMLImportLoader::shouldBlockScriptExecution() const
218 {
219     return firstImport()->state().shouldBlockScriptExecution();
220 }
221 
microtaskQueue() const222 PassRefPtrWillBeRawPtr<CustomElementSyncMicrotaskQueue> HTMLImportLoader::microtaskQueue() const
223 {
224     return m_microtaskQueue;
225 }
226 
trace(Visitor * visitor)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