• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
ResourceClient(InspectorResourceContentLoader * loader)28     ResourceClient(InspectorResourceContentLoader* loader)
29         : m_loader(loader)
30     {
31     }
32 
waitForResource(Resource * resource)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 
resourceFinished(Resource * resource)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 
setCSSStyleSheet(const String &,const KURL & url,const String &,const CSSStyleSheetResource * resource)64 void InspectorResourceContentLoader::ResourceClient::setCSSStyleSheet(const String&, const KURL& url, const String&, const CSSStyleSheetResource* resource)
65 {
66     resourceFinished(const_cast<CSSStyleSheetResource*>(resource));
67 }
68 
notifyFinished(Resource * resource)69 void InspectorResourceContentLoader::ResourceClient::notifyFinished(Resource* resource)
70 {
71     if (resource->type() == Resource::CSSStyleSheet)
72         return;
73     resourceFinished(resource);
74 }
75 
InspectorResourceContentLoader(Page * page)76 InspectorResourceContentLoader::InspectorResourceContentLoader(Page* page)
77     : m_allRequestsStarted(false)
78     , m_started(false)
79     , m_page(page)
80 {
81 }
82 
start()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 
ensureResourcesContentLoaded(VoidCallback * callback)148 void InspectorResourceContentLoader::ensureResourcesContentLoaded(VoidCallback* callback)
149 {
150     if (!m_started)
151         start();
152     m_callbacks.append(callback);
153     checkDone();
154 }
155 
~InspectorResourceContentLoader()156 InspectorResourceContentLoader::~InspectorResourceContentLoader()
157 {
158     ASSERT(m_resources.isEmpty());
159 }
160 
trace(Visitor * visitor)161 void InspectorResourceContentLoader::trace(Visitor* visitor)
162 {
163     visitor->trace(m_callbacks);
164     visitor->trace(m_page);
165 }
166 
dispose()167 void InspectorResourceContentLoader::dispose()
168 {
169     stop();
170 }
171 
stop()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 
hasFinished()183 bool InspectorResourceContentLoader::hasFinished()
184 {
185     return m_allRequestsStarted && m_pendingResourceClients.size() == 0;
186 }
187 
checkDone()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 
resourceFinished(ResourceClient * client)198 void InspectorResourceContentLoader::resourceFinished(ResourceClient* client)
199 {
200     m_pendingResourceClients.remove(client);
201     checkDone();
202 }
203 
204 } // namespace blink
205