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/frame/DOMWindow.h" 42 #include "core/frame/Frame.h" 43 #include "core/page/Page.h" 44 #include "core/page/PageGroup.h" 45 #include "core/storage/Storage.h" 46 #include "core/storage/StorageNamespace.h" 47 #include "platform/JSONValues.h" 48 #include "platform/weborigin/SecurityOrigin.h" 49 50 namespace WebCore { 51 52 namespace DOMStorageAgentState { 53 static const char domStorageAgentEnabled[] = "domStorageAgentEnabled"; 54 }; 55 56 static bool hadException(ExceptionState& exceptionState, ErrorString* errorString) 57 { 58 if (!exceptionState.hadException()) 59 return false; 60 61 switch (exceptionState.code()) { 62 case SecurityError: 63 *errorString = "Security error"; 64 return true; 65 default: 66 *errorString = "Unknown DOM storage error"; 67 return true; 68 } 69 } 70 71 InspectorDOMStorageAgent::InspectorDOMStorageAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorCompositeState* state) 72 : InspectorBaseAgent<InspectorDOMStorageAgent>("DOMStorage", instrumentingAgents, state) 73 , m_pageAgent(pageAgent) 74 , m_frontend(0) 75 { 76 } 77 78 InspectorDOMStorageAgent::~InspectorDOMStorageAgent() 79 { 80 } 81 82 void InspectorDOMStorageAgent::setFrontend(InspectorFrontend* frontend) 83 { 84 m_frontend = frontend; 85 } 86 87 void InspectorDOMStorageAgent::clearFrontend() 88 { 89 m_frontend = 0; 90 disable(0); 91 } 92 93 bool InspectorDOMStorageAgent::isEnabled() const 94 { 95 return m_state->getBoolean(DOMStorageAgentState::domStorageAgentEnabled); 96 } 97 98 void InspectorDOMStorageAgent::enable(ErrorString*) 99 { 100 m_state->setBoolean(DOMStorageAgentState::domStorageAgentEnabled, true); 101 m_instrumentingAgents->setInspectorDOMStorageAgent(this); 102 } 103 104 void InspectorDOMStorageAgent::disable(ErrorString*) 105 { 106 m_instrumentingAgents->setInspectorDOMStorageAgent(0); 107 m_state->setBoolean(DOMStorageAgentState::domStorageAgentEnabled, false); 108 } 109 110 void InspectorDOMStorageAgent::getDOMStorageItems(ErrorString* errorString, const RefPtr<JSONObject>& storageId, RefPtr<TypeBuilder::Array<TypeBuilder::Array<String> > >& items) 111 { 112 Frame* frame; 113 OwnPtr<StorageArea> storageArea = findStorageArea(errorString, storageId, frame); 114 if (!storageArea) 115 return; 116 117 RefPtr<TypeBuilder::Array<TypeBuilder::Array<String> > > storageItems = TypeBuilder::Array<TypeBuilder::Array<String> >::create(); 118 119 TrackExceptionState exceptionState; 120 for (unsigned i = 0; i < storageArea->length(exceptionState, frame); ++i) { 121 String name(storageArea->key(i, exceptionState, frame)); 122 if (hadException(exceptionState, errorString)) 123 return; 124 String value(storageArea->getItem(name, exceptionState, frame)); 125 if (hadException(exceptionState, errorString)) 126 return; 127 RefPtr<TypeBuilder::Array<String> > entry = TypeBuilder::Array<String>::create(); 128 entry->addItem(name); 129 entry->addItem(value); 130 storageItems->addItem(entry); 131 } 132 items = storageItems.release(); 133 } 134 135 static String toErrorString(ExceptionState& exceptionState) 136 { 137 if (exceptionState.hadException()) 138 return DOMException::getErrorName(exceptionState.code()); 139 return ""; 140 } 141 142 void InspectorDOMStorageAgent::setDOMStorageItem(ErrorString* errorString, const RefPtr<JSONObject>& storageId, const String& key, const String& value) 143 { 144 Frame* frame; 145 OwnPtr<StorageArea> storageArea = findStorageArea(0, storageId, frame); 146 if (!storageArea) { 147 *errorString = "Storage not found"; 148 return; 149 } 150 151 TrackExceptionState exceptionState; 152 storageArea->setItem(key, value, exceptionState, frame); 153 *errorString = toErrorString(exceptionState); 154 } 155 156 void InspectorDOMStorageAgent::removeDOMStorageItem(ErrorString* errorString, const RefPtr<JSONObject>& storageId, const String& key) 157 { 158 Frame* frame; 159 OwnPtr<StorageArea> storageArea = findStorageArea(0, storageId, frame); 160 if (!storageArea) { 161 *errorString = "Storage not found"; 162 return; 163 } 164 165 TrackExceptionState exceptionState; 166 storageArea->removeItem(key, exceptionState, frame); 167 *errorString = toErrorString(exceptionState); 168 } 169 170 String InspectorDOMStorageAgent::storageId(Storage* storage) 171 { 172 ASSERT(storage); 173 Document* document = storage->frame()->document(); 174 ASSERT(document); 175 DOMWindow* window = document->domWindow(); 176 ASSERT(window); 177 RefPtr<SecurityOrigin> securityOrigin = document->securityOrigin(); 178 bool isLocalStorage = window->optionalLocalStorage() == storage; 179 return storageId(securityOrigin.get(), isLocalStorage)->toJSONString(); 180 } 181 182 PassRefPtr<TypeBuilder::DOMStorage::StorageId> InspectorDOMStorageAgent::storageId(SecurityOrigin* securityOrigin, bool isLocalStorage) 183 { 184 return TypeBuilder::DOMStorage::StorageId::create() 185 .setSecurityOrigin(securityOrigin->toRawString()) 186 .setIsLocalStorage(isLocalStorage).release(); 187 } 188 189 void InspectorDOMStorageAgent::didDispatchDOMStorageEvent(const String& key, const String& oldValue, const String& newValue, StorageType storageType, SecurityOrigin* securityOrigin) 190 { 191 if (!m_frontend || !isEnabled()) 192 return; 193 194 RefPtr<TypeBuilder::DOMStorage::StorageId> id = storageId(securityOrigin, storageType == LocalStorage); 195 196 if (key.isNull()) 197 m_frontend->domstorage()->domStorageItemsCleared(id); 198 else if (newValue.isNull()) 199 m_frontend->domstorage()->domStorageItemRemoved(id, key); 200 else if (oldValue.isNull()) 201 m_frontend->domstorage()->domStorageItemAdded(id, key, newValue); 202 else 203 m_frontend->domstorage()->domStorageItemUpdated(id, key, oldValue, newValue); 204 } 205 206 PassOwnPtr<StorageArea> InspectorDOMStorageAgent::findStorageArea(ErrorString* errorString, const RefPtr<JSONObject>& storageId, Frame*& targetFrame) 207 { 208 String securityOrigin; 209 bool isLocalStorage = false; 210 bool success = storageId->getString("securityOrigin", &securityOrigin); 211 if (success) 212 success = storageId->getBoolean("isLocalStorage", &isLocalStorage); 213 if (!success) { 214 if (errorString) 215 *errorString = "Invalid storageId format"; 216 return nullptr; 217 } 218 219 Frame* frame = m_pageAgent->findFrameWithSecurityOrigin(securityOrigin); 220 if (!frame) { 221 if (errorString) 222 *errorString = "Frame not found for the given security origin"; 223 return nullptr; 224 } 225 targetFrame = frame; 226 227 if (isLocalStorage) 228 return StorageNamespace::localStorageArea(frame->document()->securityOrigin()); 229 return m_pageAgent->page()->sessionStorage()->storageArea(frame->document()->securityOrigin()); 230 } 231 232 } // namespace WebCore 233 234