1/*
2 * Copyright (C) 2010 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
28#if ENABLE(INSPECTOR)
29
30#include "InspectorApplicationCacheAgent.h"
31
32#include "ApplicationCacheHost.h"
33#include "DocumentLoader.h"
34#include "Frame.h"
35#include "FrameLoader.h"
36#include "InspectorPageAgent.h"
37#include "InspectorWebFrontendDispatchers.h"
38#include "InstrumentingAgents.h"
39#include "NetworkStateNotifier.h"
40#include "Page.h"
41#include "ResourceResponse.h"
42#include <inspector/InspectorValues.h>
43#include <wtf/text/StringBuilder.h>
44
45using namespace Inspector;
46
47namespace WebCore {
48
49InspectorApplicationCacheAgent::InspectorApplicationCacheAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent)
50    : InspectorAgentBase(ASCIILiteral("ApplicationCache"), instrumentingAgents)
51    , m_pageAgent(pageAgent)
52{
53}
54
55void InspectorApplicationCacheAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher)
56{
57    m_frontendDispatcher = std::make_unique<InspectorApplicationCacheFrontendDispatcher>(frontendChannel);
58    m_backendDispatcher = InspectorApplicationCacheBackendDispatcher::create(backendDispatcher, this);
59}
60
61void InspectorApplicationCacheAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason)
62{
63    m_frontendDispatcher = nullptr;
64    m_backendDispatcher.clear();
65
66    m_instrumentingAgents->setInspectorApplicationCacheAgent(nullptr);
67}
68
69void InspectorApplicationCacheAgent::enable(ErrorString*)
70{
71    m_instrumentingAgents->setInspectorApplicationCacheAgent(this);
72
73    // We need to pass initial navigator.onOnline.
74    networkStateChanged();
75}
76
77void InspectorApplicationCacheAgent::updateApplicationCacheStatus(Frame* frame)
78{
79    DocumentLoader* documentLoader = frame->loader().documentLoader();
80    if (!documentLoader)
81        return;
82
83    ApplicationCacheHost* host = documentLoader->applicationCacheHost();
84    ApplicationCacheHost::Status status = host->status();
85    ApplicationCacheHost::CacheInfo info = host->applicationCacheInfo();
86
87    String manifestURL = info.m_manifest.string();
88    m_frontendDispatcher->applicationCacheStatusUpdated(m_pageAgent->frameId(frame), manifestURL, static_cast<int>(status));
89}
90
91void InspectorApplicationCacheAgent::networkStateChanged()
92{
93    bool isNowOnline = networkStateNotifier().onLine();
94    m_frontendDispatcher->networkStateUpdated(isNowOnline);
95}
96
97void InspectorApplicationCacheAgent::getFramesWithManifests(ErrorString*, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::ApplicationCache::FrameWithManifest>>& result)
98{
99    result = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::ApplicationCache::FrameWithManifest>::create();
100
101    Frame* mainFrame = m_pageAgent->mainFrame();
102    for (Frame* frame = mainFrame; frame; frame = frame->tree().traverseNext(mainFrame)) {
103        DocumentLoader* documentLoader = frame->loader().documentLoader();
104        if (!documentLoader)
105            continue;
106
107        ApplicationCacheHost* host = documentLoader->applicationCacheHost();
108        ApplicationCacheHost::CacheInfo info = host->applicationCacheInfo();
109        String manifestURL = info.m_manifest.string();
110        if (!manifestURL.isEmpty()) {
111            RefPtr<Inspector::TypeBuilder::ApplicationCache::FrameWithManifest> value = Inspector::TypeBuilder::ApplicationCache::FrameWithManifest::create()
112                .setFrameId(m_pageAgent->frameId(frame))
113                .setManifestURL(manifestURL)
114                .setStatus(static_cast<int>(host->status()));
115            result->addItem(value);
116        }
117    }
118}
119
120DocumentLoader* InspectorApplicationCacheAgent::assertFrameWithDocumentLoader(ErrorString* errorString, String frameId)
121{
122    Frame* frame = m_pageAgent->assertFrame(errorString, frameId);
123    if (!frame)
124        return nullptr;
125
126    return InspectorPageAgent::assertDocumentLoader(errorString, frame);
127}
128
129void InspectorApplicationCacheAgent::getManifestForFrame(ErrorString* errorString, const String& frameId, String* manifestURL)
130{
131    DocumentLoader* documentLoader = assertFrameWithDocumentLoader(errorString, frameId);
132    if (!documentLoader)
133        return;
134
135    ApplicationCacheHost::CacheInfo info = documentLoader->applicationCacheHost()->applicationCacheInfo();
136    *manifestURL = info.m_manifest.string();
137}
138
139void InspectorApplicationCacheAgent::getApplicationCacheForFrame(ErrorString* errorString, const String& frameId, RefPtr<Inspector::TypeBuilder::ApplicationCache::ApplicationCache>& applicationCache)
140{
141    DocumentLoader* documentLoader = assertFrameWithDocumentLoader(errorString, frameId);
142    if (!documentLoader)
143        return;
144
145    ApplicationCacheHost* host = documentLoader->applicationCacheHost();
146    ApplicationCacheHost::CacheInfo info = host->applicationCacheInfo();
147
148    ApplicationCacheHost::ResourceInfoList resources;
149    host->fillResourceList(&resources);
150
151    applicationCache = buildObjectForApplicationCache(resources, info);
152}
153
154PassRefPtr<Inspector::TypeBuilder::ApplicationCache::ApplicationCache> InspectorApplicationCacheAgent::buildObjectForApplicationCache(const ApplicationCacheHost::ResourceInfoList& applicationCacheResources, const ApplicationCacheHost::CacheInfo& applicationCacheInfo)
155{
156    return Inspector::TypeBuilder::ApplicationCache::ApplicationCache::create()
157        .setManifestURL(applicationCacheInfo.m_manifest.string())
158        .setSize(applicationCacheInfo.m_size)
159        .setCreationTime(applicationCacheInfo.m_creationTime)
160        .setUpdateTime(applicationCacheInfo.m_updateTime)
161        .setResources(buildArrayForApplicationCacheResources(applicationCacheResources))
162        .release();
163}
164
165PassRefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::ApplicationCache::ApplicationCacheResource>> InspectorApplicationCacheAgent::buildArrayForApplicationCacheResources(const ApplicationCacheHost::ResourceInfoList& applicationCacheResources)
166{
167    RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::ApplicationCache::ApplicationCacheResource>> resources = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::ApplicationCache::ApplicationCacheResource>::create();
168
169    for (const auto& resourceInfo : applicationCacheResources)
170        resources->addItem(buildObjectForApplicationCacheResource(resourceInfo));
171
172    return resources;
173}
174
175PassRefPtr<Inspector::TypeBuilder::ApplicationCache::ApplicationCacheResource> InspectorApplicationCacheAgent::buildObjectForApplicationCacheResource(const ApplicationCacheHost::ResourceInfo& resourceInfo)
176{
177    StringBuilder types;
178
179    if (resourceInfo.m_isMaster)
180        types.appendLiteral("Master ");
181
182    if (resourceInfo.m_isManifest)
183        types.appendLiteral("Manifest ");
184
185    if (resourceInfo.m_isFallback)
186        types.appendLiteral("Fallback ");
187
188    if (resourceInfo.m_isForeign)
189        types.appendLiteral("Foreign ");
190
191    if (resourceInfo.m_isExplicit)
192        types.appendLiteral("Explicit ");
193
194    RefPtr<Inspector::TypeBuilder::ApplicationCache::ApplicationCacheResource> value = Inspector::TypeBuilder::ApplicationCache::ApplicationCacheResource::create()
195        .setUrl(resourceInfo.m_resource.string())
196        .setSize(static_cast<int>(resourceInfo.m_size))
197        .setType(types.toString());
198    return value;
199}
200
201} // namespace WebCore
202
203#endif // ENABLE(INSPECTOR)
204