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