c6fef54bf65a8ec62363dc752a277903ae755b27
[WebKit-https.git] / Source / WebCore / inspector / InjectedScriptManager.cpp
1 /*
2  * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
4  * Copyright (C) 2012 Google 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 Computer, 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
33 #if ENABLE(INSPECTOR)
34
35 #include "InjectedScriptManager.h"
36
37 #include "InjectedScript.h"
38 #include "InjectedScriptHost.h"
39 #include "InjectedScriptSource.h"
40 #include "InspectorValues.h"
41 #include "ScriptObject.h"
42 #include <wtf/PassOwnPtr.h>
43
44 namespace WebCore {
45
46 class InjectedScriptManager::ObjectIdMap {
47     WTF_MAKE_NONCOPYABLE(ObjectIdMap);
48 public:
49     ObjectIdMap() : m_nextId(1) { }
50
51     unsigned objectId(const ScriptObject& object)
52     {
53         Map::AddResult result = m_objectToId.add(object, m_nextId);
54         if (result.isNewEntry)
55             ++m_nextId;
56         return result.iterator->value;
57     }
58
59     unsigned releaseObjectId(const ScriptObject& object)
60     {
61         return m_objectToId.take(object);
62     }
63
64 private:
65
66     typedef HashMap<ScriptObject, unsigned> Map;
67     Map m_objectToId;
68     unsigned m_nextId;
69 };
70
71 PassOwnPtr<InjectedScriptManager> InjectedScriptManager::createForPage()
72 {
73     return adoptPtr(new InjectedScriptManager(&InjectedScriptManager::canAccessInspectedWindow));
74 }
75
76 PassOwnPtr<InjectedScriptManager> InjectedScriptManager::createForWorker()
77 {
78     return adoptPtr(new InjectedScriptManager(&InjectedScriptManager::canAccessInspectedWorkerContext));
79 }
80
81 InjectedScriptManager::InjectedScriptManager(InspectedStateAccessCheck accessCheck)
82     : m_nextInjectedScriptId(1)
83     , m_injectedScriptHost(InjectedScriptHost::create(this))
84     , m_inspectedStateAccessCheck(accessCheck)
85 {
86 }
87
88 InjectedScriptManager::~InjectedScriptManager()
89 {
90 }
91
92 void InjectedScriptManager::disconnect()
93 {
94     m_injectedScriptHost->disconnect();
95     m_injectedScriptHost.clear();
96 }
97
98 InjectedScriptHost* InjectedScriptManager::injectedScriptHost()
99 {
100     return m_injectedScriptHost.get();
101 }
102
103 InjectedScript InjectedScriptManager::injectedScriptForId(int id)
104 {
105     IdToInjectedScriptMap::iterator it = m_idToInjectedScript.find(id);
106     if (it != m_idToInjectedScript.end())
107         return it->value;
108     for (ScriptStateToId::iterator it = m_scriptStateToId.begin(); it != m_scriptStateToId.end(); ++it) {
109         if (it->value == id)
110             return injectedScriptFor(it->key);
111     }
112     return InjectedScript();
113 }
114
115 int InjectedScriptManager::injectedScriptIdFor(ScriptState* scriptState)
116 {
117     ScriptStateToId::iterator it = m_scriptStateToId.find(scriptState);
118     if (it != m_scriptStateToId.end())
119         return it->value;
120     int id = m_nextInjectedScriptId++;
121     m_scriptStateToId.set(scriptState, id);
122     return id;
123 }
124
125 InjectedScript InjectedScriptManager::injectedScriptForObjectId(const String& objectId)
126 {
127     RefPtr<InspectorValue> parsedObjectId = InspectorValue::parseJSON(objectId);
128     if (parsedObjectId && parsedObjectId->type() == InspectorValue::TypeObject) {
129         long injectedScriptId = 0;
130         bool success = parsedObjectId->asObject()->getNumber("injectedScriptId", &injectedScriptId);
131         if (success)
132             return m_idToInjectedScript.get(injectedScriptId);
133     }
134     return InjectedScript();
135 }
136
137 void InjectedScriptManager::discardInjectedScripts()
138 {
139     m_idToInjectedScript.clear();
140     m_scriptStateToId.clear();
141     m_scriptStateToObjectIdMap.clear();
142 }
143
144 void InjectedScriptManager::discardInjectedScriptsFor(DOMWindow* window)
145 {
146     if (m_scriptStateToId.isEmpty())
147         return;
148
149     // Destroy object id maps.
150     Vector<ScriptState*> scriptStatesToRemove;
151     for (ScriptStateToObjectIdMap::iterator it = m_scriptStateToObjectIdMap.begin(); it != m_scriptStateToObjectIdMap.end(); ++it) {
152         ScriptState* scriptState = it->key;
153         if (window == domWindowFromScriptState(scriptState))
154             scriptStatesToRemove.append(scriptState);
155     }
156     for (size_t i = 0; i < scriptStatesToRemove.size(); i++)
157         m_scriptStateToObjectIdMap.remove(scriptStatesToRemove[i]);
158
159     Vector<long> idsToRemove;
160     IdToInjectedScriptMap::iterator end = m_idToInjectedScript.end();
161     for (IdToInjectedScriptMap::iterator it = m_idToInjectedScript.begin(); it != end; ++it) {
162         ScriptState* scriptState = it->value.scriptState();
163         if (window != domWindowFromScriptState(scriptState))
164             continue;
165         m_scriptStateToId.remove(scriptState);
166         idsToRemove.append(it->key);
167     }
168
169     for (size_t i = 0; i < idsToRemove.size(); i++)
170         m_idToInjectedScript.remove(idsToRemove[i]);
171
172     // Now remove script states that have id but no injected script.
173     scriptStatesToRemove.clear();
174     for (ScriptStateToId::iterator it = m_scriptStateToId.begin(); it != m_scriptStateToId.end(); ++it) {
175         ScriptState* scriptState = it->key;
176         if (window == domWindowFromScriptState(scriptState))
177             scriptStatesToRemove.append(scriptState);
178     }
179     for (size_t i = 0; i < scriptStatesToRemove.size(); i++)
180         m_scriptStateToId.remove(scriptStatesToRemove[i]);
181 }
182
183 bool InjectedScriptManager::canAccessInspectedWorkerContext(ScriptState*)
184 {
185     return true;
186 }
187
188 void InjectedScriptManager::releaseObjectGroup(const String& objectGroup)
189 {
190     for (IdToInjectedScriptMap::iterator it = m_idToInjectedScript.begin(); it != m_idToInjectedScript.end(); ++it)
191         it->value.releaseObjectGroup(objectGroup);
192 }
193
194 unsigned InjectedScriptManager::objectId(const ScriptObject& object)
195 {
196     if (object.hasNoValue())
197         return 0;
198     ScriptState* state = object.scriptState();
199     ObjectIdMap* map = m_scriptStateToObjectIdMap.get(state);
200     if (!map) {
201         ScriptStateToObjectIdMap::AddResult result = m_scriptStateToObjectIdMap.set(state, adoptPtr(new ObjectIdMap()));
202         map = result.iterator->value.get();
203     }
204     return map->objectId(object);
205 }
206
207 unsigned InjectedScriptManager::releaseObjectId(const ScriptObject& object)
208 {
209     if (object.hasNoValue())
210         return 0;
211     ScriptState* state = object.scriptState();
212     ObjectIdMap* map = m_scriptStateToObjectIdMap.get(state);
213     if (!map)
214         return 0;
215     return map->releaseObjectId(object);
216 }
217
218 String InjectedScriptManager::injectedScriptSource()
219 {
220     return String(reinterpret_cast<const char*>(InjectedScriptSource_js), sizeof(InjectedScriptSource_js));
221 }
222
223 InjectedScript InjectedScriptManager::injectedScriptFor(ScriptState* inspectedScriptState)
224 {
225     ScriptStateToId::iterator it = m_scriptStateToId.find(inspectedScriptState);
226     if (it != m_scriptStateToId.end()) {
227         IdToInjectedScriptMap::iterator it1 = m_idToInjectedScript.find(it->value);
228         if (it1 != m_idToInjectedScript.end())
229             return it1->value;
230     }
231
232     if (!m_inspectedStateAccessCheck(inspectedScriptState))
233         return InjectedScript();
234
235     int id = injectedScriptIdFor(inspectedScriptState);
236     ScriptObject injectedScriptObject = createInjectedScript(injectedScriptSource(), inspectedScriptState, id);
237     InjectedScript result(injectedScriptObject, m_inspectedStateAccessCheck);
238     m_idToInjectedScript.set(id, result);
239     return result;
240 }
241
242 } // namespace WebCore
243
244 #endif // ENABLE(INSPECTOR)