#include "core/html/HTMLImportLoader.h"
#include "core/dom/Document.h"
-#include "core/dom/custom/CustomElementRegistrationContext.h"
#include "core/fetch/ResourceFetcher.h"
+#include "core/frame/ContentSecurityPolicyResponseHeaders.h"
#include "core/html/HTMLDocument.h"
+#include "core/html/HTMLImport.h"
#include "core/html/HTMLImportLoaderClient.h"
#include "core/loader/DocumentWriter.h"
-#include "core/frame/ContentSecurityPolicyResponseHeaders.h"
+
namespace WebCore {
-HTMLImportLoader::HTMLImportLoader(HTMLImport* parent, const KURL& url)
- : m_parent(parent)
+HTMLImportLoader::HTMLImportLoader(HTMLImport* import)
+ : m_import(import)
, m_state(StateLoading)
- , m_url(url)
{
}
HTMLImportLoader::~HTMLImportLoader()
{
- // importDestroyed() should be called before the destruction.
- ASSERT(!m_parent);
- ASSERT(!m_importedDocument);
- if (m_resource)
- m_resource->removeClient(this);
+ if (m_importedDocument)
+ m_importedDocument->setImport(0);
}
-void HTMLImportLoader::setResource(const ResourcePtr<RawResource>& resource)
+void HTMLImportLoader::startLoading(const ResourcePtr<RawResource>& resource)
{
- m_resource = resource;
- m_resource->addClient(this);
+ setResource(resource);
}
-void HTMLImportLoader::responseReceived(Resource*, const ResourceResponse& response)
+void HTMLImportLoader::responseReceived(Resource* resource, const ResourceResponse& response)
{
+ // Resource may already have been loaded with the import loader
+ // being added as a client later & now being notified. Fail early.
+ if (resource->loadFailedOrCanceled() || response.httpStatusCode() >= 400) {
+ setState(StateError);
+ return;
+ }
setState(startWritingAndParsing(response));
}
m_writer->addData(data, length);
}
-void HTMLImportLoader::notifyFinished(Resource*)
+void HTMLImportLoader::notifyFinished(Resource* resource)
{
- setState(finishWriting());
-}
-
-void HTMLImportLoader::setState(State state)
-{
- if (m_state == state)
+ // The writer instance indicates that a part of the document can be already loaded.
+ // We don't take such a case as an error because the partially-loaded document has been visible from script at this point.
+ if (resource->loadFailedOrCanceled() && !m_writer) {
+ setState(StateError);
return;
-
- m_state = state;
-
- if (m_state == StateReady || m_state == StateError || m_state == StateWritten) {
- if (RefPtr<DocumentWriter> writer = m_writer.release())
- writer->end();
}
- // Since DocumentWriter::end() let setState() reenter, we shouldn't refer to m_state here.
- if (state == StateReady || state == StateError)
- didFinish();
-}
-
-void HTMLImportLoader::didFinish()
-{
- for (size_t i = 0; i < m_clients.size(); ++i)
- m_clients[i]->didFinish();
-
- if (m_resource) {
- m_resource->removeClient(this);
- m_resource = 0;
- }
-
- ASSERT(!document() || !document()->parsing());
- root()->importWasDisposed();
+ setState(finishWriting());
}
HTMLImportLoader::State HTMLImportLoader::startWritingAndParsing(const ResourceResponse& response)
{
- // Current canAccess() implementation isn't sufficient for catching cross-domain redirects: http://crbug.com/256976
- if (!m_parent->document()->fetcher()->canAccess(m_resource.get()))
- return StateError;
-
- DocumentInit init = DocumentInit(response.url(), 0, root()->document()->contextDocument(), this)
- .withRegistrationContext(root()->document()->registrationContext());
+ DocumentInit init = DocumentInit(response.url(), 0, m_import->master()->contextDocument(), m_import)
+ .withRegistrationContext(m_import->master()->registrationContext());
m_importedDocument = HTMLDocument::create(init);
m_importedDocument->initContentSecurityPolicy(ContentSecurityPolicyResponseHeaders(response));
m_writer = DocumentWriter::create(m_importedDocument.get(), response.mimeType(), response.textEncodingName());
HTMLImportLoader::State HTMLImportLoader::finishWriting()
{
- if (!m_parent)
- return StateError;
- // The writer instance indicates that a part of the document can be already loaded.
- // We don't take such a case as an error because the partially-loaded document has been visible from script at this point.
- if (m_resource->loadFailedOrCanceled() && !m_writer)
- return StateError;
-
return StateWritten;
}
HTMLImportLoader::State HTMLImportLoader::finishParsing()
{
- if (!m_parent)
- return StateError;
return StateReady;
}
-Document* HTMLImportLoader::importedDocument() const
-{
- if (m_state == StateError)
- return 0;
- return m_importedDocument.get();
-}
-
-void HTMLImportLoader::addClient(HTMLImportLoaderClient* client)
+void HTMLImportLoader::setState(State state)
{
- ASSERT(kNotFound == m_clients.find(client));
- m_clients.append(client);
- if (isDone())
- client->didFinish();
-}
+ if (m_state == state)
+ return;
-void HTMLImportLoader::removeClient(HTMLImportLoaderClient* client)
-{
- ASSERT(kNotFound != m_clients.find(client));
- m_clients.remove(m_clients.find(client));
-}
+ m_state = state;
-void HTMLImportLoader::importDestroyed()
-{
- m_parent = 0;
- if (RefPtr<Document> document = m_importedDocument.release())
- document->setImport(0);
-}
+ if (m_state == StateReady || m_state == StateError || m_state == StateWritten) {
+ if (RefPtr<DocumentWriter> writer = m_writer.release())
+ writer->end();
+ }
-HTMLImportRoot* HTMLImportLoader::root()
-{
- return m_parent ? m_parent->root() : 0;
+ // Since DocumentWriter::end() can let setState() reenter, we shouldn't refer to m_state here.
+ if (state == StateReady || state == StateError)
+ didFinish();
}
-HTMLImport* HTMLImportLoader::parent() const
+void HTMLImportLoader::didFinishParsing()
{
- return m_parent;
+ setState(finishParsing());
}
-Document* HTMLImportLoader::document() const
+Document* HTMLImportLoader::importedDocument() const
{
+ if (m_state == StateError)
+ return 0;
return m_importedDocument.get();
}
-void HTMLImportLoader::wasDetachedFromDocument()
+void HTMLImportLoader::didFinish()
{
- // For imported documens this shouldn't be called because Document::m_import is
- // cleared before Document is destroyed by HTMLImportLoader::importDestroyed().
- ASSERT_NOT_REACHED();
+ for (size_t i = 0; i < m_clients.size(); ++i)
+ m_clients[i]->didFinishLoading();
+
+ clearResource();
+
+ ASSERT(!m_importedDocument || !m_importedDocument->parsing());
}
-void HTMLImportLoader::didFinishParsing()
+void HTMLImportLoader::addClient(HTMLImportLoaderClient* client)
{
- setState(finishParsing());
+ ASSERT(kNotFound == m_clients.find(client));
+ m_clients.append(client);
+ if (isDone())
+ client->didFinishLoading();
}
-bool HTMLImportLoader::isProcessing() const
+void HTMLImportLoader::removeClient(HTMLImportLoaderClient* client)
{
- if (!m_importedDocument)
- return !isDone();
- return m_importedDocument->parsing();
+ ASSERT(kNotFound != m_clients.find(client));
+ m_clients.remove(m_clients.find(client));
}
} // namespace WebCore