1/*
2 * Copyright (C) 2010, 2015 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 Google Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "InspectorApplicationCacheAgent.h"
28
29#include "ApplicationCacheHost.h"
30#include "DocumentLoader.h"
31#include "Frame.h"
32#include "FrameLoader.h"
33#include "InspectorPageAgent.h"
34#include "InstrumentingAgents.h"
35#include "LoaderStrategy.h"
36#include "Page.h"
37#include "PlatformStrategies.h"
38#include <wtf/text/StringBuilder.h>
39
40namespace WebCore {
41
42using namespace Inspector;
43
44InspectorApplicationCacheAgent::InspectorApplicationCacheAgent(PageAgentContext& context)
45 : InspectorAgentBase("ApplicationCache"_s, context)
46 , m_frontendDispatcher(std::make_unique<Inspector::ApplicationCacheFrontendDispatcher>(context.frontendRouter))
47 , m_backendDispatcher(Inspector::ApplicationCacheBackendDispatcher::create(context.backendDispatcher, this))
48 , m_inspectedPage(context.inspectedPage)
49{
50}
51
52void InspectorApplicationCacheAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*)
53{
54}
55
56void InspectorApplicationCacheAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
57{
58 m_instrumentingAgents.setInspectorApplicationCacheAgent(nullptr);
59}
60
61void InspectorApplicationCacheAgent::enable(ErrorString&)
62{
63 m_instrumentingAgents.setInspectorApplicationCacheAgent(this);
64
65 // We need to pass initial navigator.onOnline.
66 networkStateChanged();
67}
68
69void InspectorApplicationCacheAgent::updateApplicationCacheStatus(Frame* frame)
70{
71 auto* pageAgent = m_instrumentingAgents.inspectorPageAgent();
72 if (!pageAgent)
73 return;
74
75 if (!frame)
76 return;
77
78 auto* documentLoader = frame->loader().documentLoader();
79 if (!documentLoader)
80 return;
81
82 auto& host = documentLoader->applicationCacheHost();
83 int status = host.status();
84 auto manifestURL = host.applicationCacheInfo().manifest.string();
85
86 m_frontendDispatcher->applicationCacheStatusUpdated(pageAgent->frameId(frame), manifestURL, status);
87}
88
89void InspectorApplicationCacheAgent::networkStateChanged()
90{
91 m_frontendDispatcher->networkStateUpdated(platformStrategies()->loaderStrategy()->isOnLine());
92}
93
94void InspectorApplicationCacheAgent::getFramesWithManifests(ErrorString&, RefPtr<JSON::ArrayOf<Inspector::Protocol::ApplicationCache::FrameWithManifest>>& result)
95{
96 result = JSON::ArrayOf<Inspector::Protocol::ApplicationCache::FrameWithManifest>::create();
97
98 auto* pageAgent = m_instrumentingAgents.inspectorPageAgent();
99
100 for (Frame* frame = &m_inspectedPage.mainFrame(); frame; frame = frame->tree().traverseNext()) {
101 auto* documentLoader = frame->loader().documentLoader();
102 if (!documentLoader)
103 continue;
104
105 auto& host = documentLoader->applicationCacheHost();
106 String manifestURL = host.applicationCacheInfo().manifest.string();
107 if (!manifestURL.isEmpty()) {
108 result->addItem(Inspector::Protocol::ApplicationCache::FrameWithManifest::create()
109 .setFrameId(pageAgent->frameId(frame))
110 .setManifestURL(manifestURL)
111 .setStatus(static_cast<int>(host.status()))
112 .release());
113 }
114 }
115}
116
117DocumentLoader* InspectorApplicationCacheAgent::assertFrameWithDocumentLoader(ErrorString& errorString, const String& frameId)
118{
119 auto* pageAgent = m_instrumentingAgents.inspectorPageAgent();
120 if (!pageAgent) {
121 errorString = "Missing Page agent"_s;
122 return nullptr;
123 }
124
125 Frame* frame = pageAgent->assertFrame(errorString, frameId);
126 if (!frame)
127 return nullptr;
128
129 return InspectorPageAgent::assertDocumentLoader(errorString, frame);
130}
131
132void InspectorApplicationCacheAgent::getManifestForFrame(ErrorString& errorString, const String& frameId, String* manifestURL)
133{
134 DocumentLoader* documentLoader = assertFrameWithDocumentLoader(errorString, frameId);
135 if (!documentLoader)
136 return;
137
138 *manifestURL = documentLoader->applicationCacheHost().applicationCacheInfo().manifest.string();
139}
140
141void InspectorApplicationCacheAgent::getApplicationCacheForFrame(ErrorString& errorString, const String& frameId, RefPtr<Inspector::Protocol::ApplicationCache::ApplicationCache>& applicationCache)
142{
143 auto* documentLoader = assertFrameWithDocumentLoader(errorString, frameId);
144 if (!documentLoader)
145 return;
146
147 auto& host = documentLoader->applicationCacheHost();
148 applicationCache = buildObjectForApplicationCache(host.resourceList(), host.applicationCacheInfo());
149}
150
151Ref<Inspector::Protocol::ApplicationCache::ApplicationCache> InspectorApplicationCacheAgent::buildObjectForApplicationCache(const Vector<ApplicationCacheHost::ResourceInfo>& applicationCacheResources, const ApplicationCacheHost::CacheInfo& applicationCacheInfo)
152{
153 return Inspector::Protocol::ApplicationCache::ApplicationCache::create()
154 .setManifestURL(applicationCacheInfo.manifest.string())
155 .setSize(applicationCacheInfo.size)
156 .setCreationTime(applicationCacheInfo.creationTime)
157 .setUpdateTime(applicationCacheInfo.updateTime)
158 .setResources(buildArrayForApplicationCacheResources(applicationCacheResources))
159 .release();
160}
161
162Ref<JSON::ArrayOf<Inspector::Protocol::ApplicationCache::ApplicationCacheResource>> InspectorApplicationCacheAgent::buildArrayForApplicationCacheResources(const Vector<ApplicationCacheHost::ResourceInfo>& applicationCacheResources)
163{
164 auto result = JSON::ArrayOf<Inspector::Protocol::ApplicationCache::ApplicationCacheResource>::create();
165 for (auto& info : applicationCacheResources)
166 result->addItem(buildObjectForApplicationCacheResource(info));
167 return result;
168}
169
170Ref<Inspector::Protocol::ApplicationCache::ApplicationCacheResource> InspectorApplicationCacheAgent::buildObjectForApplicationCacheResource(const ApplicationCacheHost::ResourceInfo& resourceInfo)
171{
172 StringBuilder types;
173
174 if (resourceInfo.isMaster)
175 types.appendLiteral("Master ");
176
177 if (resourceInfo.isManifest)
178 types.appendLiteral("Manifest ");
179
180 if (resourceInfo.isFallback)
181 types.appendLiteral("Fallback ");
182
183 if (resourceInfo.isForeign)
184 types.appendLiteral("Foreign ");
185
186 if (resourceInfo.isExplicit)
187 types.appendLiteral("Explicit ");
188
189 return Inspector::Protocol::ApplicationCache::ApplicationCacheResource::create()
190 .setUrl(resourceInfo.resource.string())
191 .setSize(static_cast<int>(resourceInfo.size))
192 .setType(types.toString())
193 .release();
194}
195
196} // namespace WebCore
197