1 /* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * Copyright (C) 2013 Samsung Electronics. 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 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "config.h" 31 #include "core/inspector/InspectorDOMStorageAgent.h" 32 33 #include "InspectorFrontend.h" 34 #include "bindings/v8/ExceptionState.h" 35 #include "core/dom/DOMException.h" 36 #include "core/dom/Document.h" 37 #include "core/dom/ExceptionCode.h" 38 #include "core/inspector/InspectorPageAgent.h" 39 #include "core/inspector/InspectorState.h" 40 #include "core/inspector/InstrumentingAgents.h" 41 #include "core/page/DOMWindow.h" 42 #include "core/page/Frame.h" 43 #include "core/page/Page.h" 44 #include "core/page/PageGroup.h" 45 #include "core/platform/JSONValues.h" 46 #include "core/storage/Storage.h" 47 #include "core/storage/StorageArea.h" 48 #include "core/storage/StorageNamespace.h" 49 #include "weborigin/SecurityOrigin.h" 50 51 namespace WebCore { 52 53 namespace DOMStorageAgentState { 54 static const char domStorageAgentEnabled[] = "domStorageAgentEnabled"; 55 }; 56 57 static bool hadException(ExceptionState& es, ErrorString* errorString) 58 { 59 if (!es.hadException()) 60 return false; 61 62 switch (es.code()) { 63 case SecurityError: 64 *errorString = "Security error"; 65 return true; 66 default: 67 *errorString = "Unknown DOM storage error"; 68 return true; 69 } 70 } 71 72 InspectorDOMStorageAgent::InspectorDOMStorageAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorCompositeState* state) 73 : InspectorBaseAgent<InspectorDOMStorageAgent>("DOMStorage", instrumentingAgents, state) 74 , m_pageAgent(pageAgent) 75 , m_frontend(0) 76 { 77 } 78 79 InspectorDOMStorageAgent::~InspectorDOMStorageAgent() 80 { 81 } 82 83 void InspectorDOMStorageAgent::setFrontend(InspectorFrontend* frontend) 84 { 85 m_frontend = frontend; 86 } 87 88 void InspectorDOMStorageAgent::clearFrontend() 89 { 90 m_frontend = 0; 91 disable(0); 92 } 93 94 bool InspectorDOMStorageAgent::isEnabled() const 95 { 96 return m_state->getBoolean(DOMStorageAgentState::domStorageAgentEnabled); 97 } 98 99 void InspectorDOMStorageAgent::enable(ErrorString*) 100 { 101 m_state->setBoolean(DOMStorageAgentState::domStorageAgentEnabled, true); 102 m_instrumentingAgents->setInspectorDOMStorageAgent(this); 103 } 104 105 void InspectorDOMStorageAgent::disable(ErrorString*) 106 { 107 m_instrumentingAgents->setInspectorDOMStorageAgent(0); 108 m_state->setBoolean(DOMStorageAgentState::domStorageAgentEnabled, false); 109 } 110 111 void InspectorDOMStorageAgent::getValue(ErrorString* errorString, const RefPtr<JSONObject>& storageId, const String& key, TypeBuilder::OptOutput<WTF::String>* value) 112 { 113 Frame* frame; 114 OwnPtr<StorageArea> storageArea = findStorageArea(errorString, storageId, frame); 115 if (!storageArea) 116 return; 117 118 TrackExceptionState es; 119 bool keyPresent = storageArea->contains(key, es, frame); 120 if (hadException(es, errorString) || !keyPresent) 121 return; 122 123 *value = storageArea->getItem(key, es, frame); 124 hadException(es, errorString); 125 } 126 127 void InspectorDOMStorageAgent::getDOMStorageItems(ErrorString* errorString, const RefPtr<JSONObject>& storageId, RefPtr<TypeBuilder::Array<TypeBuilder::Array<String> > >& items) 128 { 129 Frame* frame; 130 OwnPtr<StorageArea> storageArea = findStorageArea(errorString, storageId, frame); 131 if (!storageArea) 132 return; 133 134 RefPtr<TypeBuilder::Array<TypeBuilder::Array<String> > > storageItems = TypeBuilder::Array<TypeBuilder::Array<String> >::create(); 135 136 TrackExceptionState es; 137 for (unsigned i = 0; i < storageArea->length(es, frame); ++i) { 138 String name(storageArea->key(i, es, frame)); 139 if (hadException(es, errorString)) 140 return; 141 String value(storageArea->getItem(name, es, frame)); 142 if (hadException(es, errorString)) 143 return; 144 RefPtr<TypeBuilder::Array<String> > entry = TypeBuilder::Array<String>::create(); 145 entry->addItem(name); 146 entry->addItem(value); 147 storageItems->addItem(entry); 148 } 149 items = storageItems.release(); 150 } 151 152 static String toErrorString(ExceptionState& es) 153 { 154 if (es.hadException()) 155 return DOMException::getErrorName(es.code()); 156 return ""; 157 } 158 159 void InspectorDOMStorageAgent::setDOMStorageItem(ErrorString* errorString, const RefPtr<JSONObject>& storageId, const String& key, const String& value) 160 { 161 Frame* frame; 162 OwnPtr<StorageArea> storageArea = findStorageArea(0, storageId, frame); 163 if (!storageArea) { 164 *errorString = "Storage not found"; 165 return; 166 } 167 168 TrackExceptionState es; 169 storageArea->setItem(key, value, es, frame); 170 *errorString = toErrorString(es); 171 } 172 173 void InspectorDOMStorageAgent::removeDOMStorageItem(ErrorString* errorString, const RefPtr<JSONObject>& storageId, const String& key) 174 { 175 Frame* frame; 176 OwnPtr<StorageArea> storageArea = findStorageArea(0, storageId, frame); 177 if (!storageArea) { 178 *errorString = "Storage not found"; 179 return; 180 } 181 182 TrackExceptionState es; 183 storageArea->removeItem(key, es, frame); 184 *errorString = toErrorString(es); 185 } 186 187 String InspectorDOMStorageAgent::storageId(Storage* storage) 188 { 189 ASSERT(storage); 190 Document* document = storage->frame()->document(); 191 ASSERT(document); 192 DOMWindow* window = document->domWindow(); 193 ASSERT(window); 194 RefPtr<SecurityOrigin> securityOrigin = document->securityOrigin(); 195 bool isLocalStorage = window->optionalLocalStorage() == storage; 196 return storageId(securityOrigin.get(), isLocalStorage)->toJSONString(); 197 } 198 199 PassRefPtr<TypeBuilder::DOMStorage::StorageId> InspectorDOMStorageAgent::storageId(SecurityOrigin* securityOrigin, bool isLocalStorage) 200 { 201 return TypeBuilder::DOMStorage::StorageId::create() 202 .setSecurityOrigin(securityOrigin->toRawString()) 203 .setIsLocalStorage(isLocalStorage).release(); 204 } 205 206 void InspectorDOMStorageAgent::didDispatchDOMStorageEvent(const String& key, const String& oldValue, const String& newValue, StorageType storageType, SecurityOrigin* securityOrigin) 207 { 208 if (!m_frontend || !isEnabled()) 209 return; 210 211 RefPtr<TypeBuilder::DOMStorage::StorageId> id = storageId(securityOrigin, storageType == LocalStorage); 212 213 if (key.isNull()) 214 m_frontend->domstorage()->domStorageItemsCleared(id); 215 else if (newValue.isNull()) 216 m_frontend->domstorage()->domStorageItemRemoved(id, key); 217 else if (oldValue.isNull()) 218 m_frontend->domstorage()->domStorageItemAdded(id, key, newValue); 219 else 220 m_frontend->domstorage()->domStorageItemUpdated(id, key, oldValue, newValue); 221 } 222 223 PassOwnPtr<StorageArea> InspectorDOMStorageAgent::findStorageArea(ErrorString* errorString, const RefPtr<JSONObject>& storageId, Frame*& targetFrame) 224 { 225 String securityOrigin; 226 bool isLocalStorage = false; 227 bool success = storageId->getString("securityOrigin", &securityOrigin); 228 if (success) 229 success = storageId->getBoolean("isLocalStorage", &isLocalStorage); 230 if (!success) { 231 if (errorString) 232 *errorString = "Invalid storageId format"; 233 return nullptr; 234 } 235 236 Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin); 237 if (!frame) { 238 if (errorString) 239 *errorString = "Frame not found for the given security origin"; 240 return nullptr; 241 } 242 targetFrame = frame; 243 244 if (isLocalStorage) 245 return StorageNamespace::localStorageArea(frame->document()->securityOrigin()); 246 return m_pageAgent->page()->sessionStorage()->storageArea(frame->document()->securityOrigin()); 247 } 248 249 } // namespace WebCore 250 251