Home | History | Annotate | Download | only in inspector
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "config.h"
      6 #include "core/inspector/InspectorResourceContentLoader.h"
      7 
      8 #include "core/FetchInitiatorTypeNames.h"
      9 #include "core/css/CSSStyleSheet.h"
     10 #include "core/css/StyleSheetContents.h"
     11 #include "core/fetch/CSSStyleSheetResource.h"
     12 #include "core/fetch/RawResource.h"
     13 #include "core/fetch/Resource.h"
     14 #include "core/fetch/ResourceFetcher.h"
     15 #include "core/fetch/ResourcePtr.h"
     16 #include "core/fetch/StyleSheetResourceClient.h"
     17 #include "core/frame/LocalFrame.h"
     18 #include "core/html/VoidCallback.h"
     19 #include "core/inspector/InspectorCSSAgent.h"
     20 #include "core/inspector/InspectorPageAgent.h"
     21 #include "core/page/Page.h"
     22 #include "public/platform/WebURLRequest.h"
     23 
     24 namespace blink {
     25 
     26 class InspectorResourceContentLoader::ResourceClient FINAL : private RawResourceClient, private StyleSheetResourceClient {
     27 public:
     28     ResourceClient(InspectorResourceContentLoader* loader)
     29         : m_loader(loader)
     30     {
     31     }
     32 
     33     void waitForResource(Resource* resource)
     34     {
     35         if (resource->type() == Resource::Raw)
     36             resource->addClient(static_cast<RawResourceClient*>(this));
     37         else
     38             resource->addClient(static_cast<StyleSheetResourceClient*>(this));
     39     }
     40 
     41 private:
     42     InspectorResourceContentLoader* m_loader;
     43 
     44     virtual void setCSSStyleSheet(const String&, const KURL&, const String&, const CSSStyleSheetResource*) OVERRIDE;
     45     virtual void notifyFinished(Resource*) OVERRIDE;
     46     void resourceFinished(Resource*);
     47 
     48     friend class InspectorResourceContentLoader;
     49 };
     50 
     51 void InspectorResourceContentLoader::ResourceClient::resourceFinished(Resource* resource)
     52 {
     53     if (m_loader)
     54         m_loader->resourceFinished(this);
     55 
     56     if (resource->type() == Resource::Raw)
     57         resource->removeClient(static_cast<RawResourceClient*>(this));
     58     else
     59         resource->removeClient(static_cast<StyleSheetResourceClient*>(this));
     60 
     61     delete this;
     62 }
     63 
     64 void InspectorResourceContentLoader::ResourceClient::setCSSStyleSheet(const String&, const KURL& url, const String&, const CSSStyleSheetResource* resource)
     65 {
     66     resourceFinished(const_cast<CSSStyleSheetResource*>(resource));
     67 }
     68 
     69 void InspectorResourceContentLoader::ResourceClient::notifyFinished(Resource* resource)
     70 {
     71     if (resource->type() == Resource::CSSStyleSheet)
     72         return;
     73     resourceFinished(resource);
     74 }
     75 
     76 InspectorResourceContentLoader::InspectorResourceContentLoader(Page* page)
     77     : m_allRequestsStarted(false)
     78     , m_started(false)
     79     , m_page(page)
     80 {
     81 }
     82 
     83 void InspectorResourceContentLoader::start()
     84 {
     85     m_started = true;
     86     Vector<Document*> documents;
     87     for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
     88         if (!frame->isLocalFrame())
     89             continue;
     90         LocalFrame* localFrame = toLocalFrame(frame);
     91         documents.append(localFrame->document());
     92         documents.appendVector(InspectorPageAgent::importsForFrame(localFrame));
     93     }
     94     for (Vector<Document*>::const_iterator documentIt = documents.begin(); documentIt != documents.end(); ++documentIt) {
     95         Document* document = *documentIt;
     96         HashSet<String> urlsToFetch;
     97 
     98         ResourceRequest resourceRequest;
     99         HistoryItem* item = document->frame() ? document->frame()->loader().currentItem() : 0;
    100         if (item) {
    101             resourceRequest = FrameLoader::requestFromHistoryItem(item, ReturnCacheDataDontLoad);
    102         } else {
    103             resourceRequest = document->url();
    104             resourceRequest.setCachePolicy(ReturnCacheDataDontLoad);
    105         }
    106         resourceRequest.setRequestContext(blink::WebURLRequest::RequestContextInternal);
    107 
    108         if (!resourceRequest.url().string().isEmpty()) {
    109             urlsToFetch.add(resourceRequest.url().string());
    110             FetchRequest request(resourceRequest, FetchInitiatorTypeNames::internal);
    111             ResourcePtr<Resource> resource = document->fetcher()->fetchRawResource(request);
    112             if (resource) {
    113                 // Prevent garbage collection by holding a reference to this resource.
    114                 m_resources.append(resource.get());
    115                 ResourceClient* resourceClient = new ResourceClient(this);
    116                 m_pendingResourceClients.add(resourceClient);
    117                 resourceClient->waitForResource(resource.get());
    118             }
    119         }
    120 
    121         WillBeHeapVector<RawPtrWillBeMember<CSSStyleSheet> > styleSheets;
    122         InspectorCSSAgent::collectAllDocumentStyleSheets(document, styleSheets);
    123         for (WillBeHeapVector<RawPtrWillBeMember<CSSStyleSheet> >::const_iterator stylesheetIt = styleSheets.begin(); stylesheetIt != styleSheets.end(); ++stylesheetIt) {
    124             CSSStyleSheet* styleSheet = *stylesheetIt;
    125             if (styleSheet->isInline() || !styleSheet->contents()->loadCompleted())
    126                 continue;
    127             String url = styleSheet->baseURL().string();
    128             if (url.isEmpty() || urlsToFetch.contains(url))
    129                 continue;
    130             urlsToFetch.add(url);
    131             FetchRequest request(ResourceRequest(url), FetchInitiatorTypeNames::internal);
    132             request.mutableResourceRequest().setRequestContext(blink::WebURLRequest::RequestContextInternal);
    133             ResourcePtr<Resource> resource = document->fetcher()->fetchCSSStyleSheet(request);
    134             if (!resource)
    135                 continue;
    136             // Prevent garbage collection by holding a reference to this resource.
    137             m_resources.append(resource.get());
    138             ResourceClient* resourceClient = new ResourceClient(this);
    139             m_pendingResourceClients.add(resourceClient);
    140             resourceClient->waitForResource(resource.get());
    141         }
    142     }
    143 
    144     m_allRequestsStarted = true;
    145     checkDone();
    146 }
    147 
    148 void InspectorResourceContentLoader::ensureResourcesContentLoaded(VoidCallback* callback)
    149 {
    150     if (!m_started)
    151         start();
    152     m_callbacks.append(callback);
    153     checkDone();
    154 }
    155 
    156 InspectorResourceContentLoader::~InspectorResourceContentLoader()
    157 {
    158     ASSERT(m_resources.isEmpty());
    159 }
    160 
    161 void InspectorResourceContentLoader::trace(Visitor* visitor)
    162 {
    163     visitor->trace(m_callbacks);
    164     visitor->trace(m_page);
    165 }
    166 
    167 void InspectorResourceContentLoader::dispose()
    168 {
    169     stop();
    170 }
    171 
    172 void InspectorResourceContentLoader::stop()
    173 {
    174     HashSet<ResourceClient*> pendingResourceClients;
    175     m_pendingResourceClients.swap(pendingResourceClients);
    176     for (HashSet<ResourceClient*>::const_iterator it = pendingResourceClients.begin(); it != pendingResourceClients.end(); ++it)
    177         (*it)->m_loader = 0;
    178     m_resources.clear();
    179     // Make sure all callbacks are called to prevent infinite waiting time.
    180     checkDone();
    181 }
    182 
    183 bool InspectorResourceContentLoader::hasFinished()
    184 {
    185     return m_allRequestsStarted && m_pendingResourceClients.size() == 0;
    186 }
    187 
    188 void InspectorResourceContentLoader::checkDone()
    189 {
    190     if (!hasFinished())
    191         return;
    192     PersistentHeapVectorWillBeHeapVector<Member<VoidCallback> > callbacks;
    193     callbacks.swap(m_callbacks);
    194     for (PersistentHeapVectorWillBeHeapVector<Member<VoidCallback> >::const_iterator it = callbacks.begin(); it != callbacks.end(); ++it)
    195         (*it)->handleEvent();
    196 }
    197 
    198 void InspectorResourceContentLoader::resourceFinished(ResourceClient* client)
    199 {
    200     m_pendingResourceClients.remove(client);
    201     checkDone();
    202 }
    203 
    204 } // namespace blink
    205