0d25da0033a64e214081762887add2218449d652
[WebKit-https.git] / Source / WebCore / inspector / agents / InspectorDOMStorageAgent.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  * Copyright (C) 2013 Samsung Electronics. All rights reserved.
4  * Copyright (C) 2015 Apple Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1.  Redistributions of source code must retain the above copyright
11  *     notice, this list of conditions and the following disclaimer.
12  * 2.  Redistributions in binary form must reproduce the above copyright
13  *     notice, this list of conditions and the following disclaimer in the
14  *     documentation and/or other materials provided with the distribution.
15  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
16  *     its contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "InspectorDOMStorageAgent.h"
33
34 #include "DOMException.h"
35 #include "DOMWindow.h"
36 #include "Database.h"
37 #include "Document.h"
38 #include "Frame.h"
39 #include "InspectorPageAgent.h"
40 #include "InstrumentingAgents.h"
41 #include "Page.h"
42 #include "SecurityOrigin.h"
43 #include "SecurityOriginData.h"
44 #include "Storage.h"
45 #include "StorageNamespace.h"
46 #include "StorageNamespaceProvider.h"
47 #include "StorageType.h"
48 #include "VoidCallback.h"
49 #include <JavaScriptCore/InspectorFrontendDispatchers.h>
50 #include <wtf/JSONValues.h>
51
52
53 namespace WebCore {
54
55 using namespace Inspector;
56
57 InspectorDOMStorageAgent::InspectorDOMStorageAgent(WebAgentContext& context, InspectorPageAgent* pageAgent)
58     : InspectorAgentBase(ASCIILiteral("DOMStorage"), context)
59     , m_frontendDispatcher(std::make_unique<Inspector::DOMStorageFrontendDispatcher>(context.frontendRouter))
60     , m_backendDispatcher(Inspector::DOMStorageBackendDispatcher::create(context.backendDispatcher, this))
61     , m_pageAgent(pageAgent)
62 {
63     m_instrumentingAgents.setInspectorDOMStorageAgent(this);
64 }
65
66 InspectorDOMStorageAgent::~InspectorDOMStorageAgent()
67 {
68     m_instrumentingAgents.setInspectorDOMStorageAgent(nullptr);
69 }
70
71 void InspectorDOMStorageAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*)
72 {
73 }
74
75 void InspectorDOMStorageAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
76 {
77     ErrorString unused;
78     disable(unused);
79 }
80
81 void InspectorDOMStorageAgent::enable(ErrorString&)
82 {
83     m_enabled = true;
84 }
85
86 void InspectorDOMStorageAgent::disable(ErrorString&)
87 {
88     m_enabled = false;
89 }
90
91 void InspectorDOMStorageAgent::getDOMStorageItems(ErrorString& errorString, const JSON::Object& storageId, RefPtr<JSON::ArrayOf<JSON::ArrayOf<String>>>& items)
92 {
93     Frame* frame;
94     RefPtr<StorageArea> storageArea = findStorageArea(errorString, storageId, frame);
95     if (!storageArea) {
96         errorString = ASCIILiteral("No StorageArea for given storageId");
97         return;
98     }
99
100     auto storageItems = JSON::ArrayOf<JSON::ArrayOf<String>>::create();
101
102     for (unsigned i = 0; i < storageArea->length(); ++i) {
103         String key = storageArea->key(i);
104         String value = storageArea->item(key);
105
106         auto entry = JSON::ArrayOf<String>::create();
107         entry->addItem(key);
108         entry->addItem(value);
109         storageItems->addItem(WTFMove(entry));
110     }
111
112     items = WTFMove(storageItems);
113 }
114
115 void InspectorDOMStorageAgent::setDOMStorageItem(ErrorString& errorString, const JSON::Object& storageId, const String& key, const String& value)
116 {
117     Frame* frame;
118     RefPtr<StorageArea> storageArea = findStorageArea(errorString, storageId, frame);
119     if (!storageArea) {
120         errorString = ASCIILiteral("Storage not found");
121         return;
122     }
123
124     bool quotaException = false;
125     storageArea->setItem(frame, key, value, quotaException);
126     if (quotaException)
127         errorString = DOMException::name(QuotaExceededError);
128 }
129
130 void InspectorDOMStorageAgent::removeDOMStorageItem(ErrorString& errorString, const JSON::Object& storageId, const String& key)
131 {
132     Frame* frame;
133     RefPtr<StorageArea> storageArea = findStorageArea(errorString, storageId, frame);
134     if (!storageArea) {
135         errorString = ASCIILiteral("Storage not found");
136         return;
137     }
138
139     storageArea->removeItem(frame, key);
140 }
141
142 String InspectorDOMStorageAgent::storageId(Storage& storage)
143 {
144     Document* document = storage.frame()->document();
145     ASSERT(document);
146     DOMWindow* window = document->domWindow();
147     ASSERT(window);
148     Ref<SecurityOrigin> securityOrigin = document->securityOrigin();
149     bool isLocalStorage = window->optionalLocalStorage() == &storage;
150     return storageId(securityOrigin.ptr(), isLocalStorage)->toJSONString();
151 }
152
153 RefPtr<Inspector::Protocol::DOMStorage::StorageId> InspectorDOMStorageAgent::storageId(SecurityOrigin* securityOrigin, bool isLocalStorage)
154 {
155     return Inspector::Protocol::DOMStorage::StorageId::create()
156         .setSecurityOrigin(securityOrigin->toRawString())
157         .setIsLocalStorage(isLocalStorage)
158         .release();
159 }
160
161 void InspectorDOMStorageAgent::didDispatchDOMStorageEvent(const String& key, const String& oldValue, const String& newValue, StorageType storageType, SecurityOrigin* securityOrigin)
162 {
163     if (!m_enabled)
164         return;
165
166     RefPtr<Inspector::Protocol::DOMStorage::StorageId> id = storageId(securityOrigin, storageType == StorageType::Local);
167
168     if (key.isNull())
169         m_frontendDispatcher->domStorageItemsCleared(id);
170     else if (newValue.isNull())
171         m_frontendDispatcher->domStorageItemRemoved(id, key);
172     else if (oldValue.isNull())
173         m_frontendDispatcher->domStorageItemAdded(id, key, newValue);
174     else
175         m_frontendDispatcher->domStorageItemUpdated(id, key, oldValue, newValue);
176 }
177
178 RefPtr<StorageArea> InspectorDOMStorageAgent::findStorageArea(ErrorString& errorString, const JSON::Object& storageId, Frame*& targetFrame)
179 {
180     String securityOrigin;
181     bool isLocalStorage = false;
182     bool success = storageId.getString(ASCIILiteral("securityOrigin"), securityOrigin);
183     if (success)
184         success = storageId.getBoolean(ASCIILiteral("isLocalStorage"), isLocalStorage);
185     if (!success) {
186         errorString = ASCIILiteral("Invalid storageId format");
187         targetFrame = nullptr;
188         return nullptr;
189     }
190
191     targetFrame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin);
192     if (!targetFrame) {
193         errorString = ASCIILiteral("Frame not found for the given security origin");
194         return nullptr;
195     }
196
197     if (!isLocalStorage)
198         return m_pageAgent->page().sessionStorage()->storageArea(SecurityOriginData::fromSecurityOrigin(targetFrame->document()->securityOrigin()));
199     return m_pageAgent->page().storageNamespaceProvider().localStorageArea(*targetFrame->document());
200 }
201
202 } // namespace WebCore