1/*
2 * Copyright (C) 2007, 2008, 2013 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 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 "InjectedScriptManager.h"
33
34#if ENABLE(INSPECTOR)
35
36#include "Completion.h"
37#include "InjectedScriptHost.h"
38#include "InjectedScriptSource.h"
39#include "InspectorValues.h"
40#include "JSInjectedScriptHost.h"
41#include "JSLock.h"
42#include "ScriptObject.h"
43#include "SourceCode.h"
44
45using namespace JSC;
46
47namespace Inspector {
48
49InjectedScriptManager::InjectedScriptManager(InspectorEnvironment& environment, PassRefPtr<InjectedScriptHost> injectedScriptHost)
50    : m_environment(environment)
51    , m_injectedScriptHost(injectedScriptHost)
52    , m_nextInjectedScriptId(1)
53{
54}
55
56InjectedScriptManager::~InjectedScriptManager()
57{
58}
59
60void InjectedScriptManager::disconnect()
61{
62    discardInjectedScripts();
63}
64
65InjectedScriptHost* InjectedScriptManager::injectedScriptHost()
66{
67    return m_injectedScriptHost.get();
68}
69
70InjectedScript InjectedScriptManager::injectedScriptForId(int id)
71{
72    auto it = m_idToInjectedScript.find(id);
73    if (it != m_idToInjectedScript.end())
74        return it->value;
75
76    for (auto it = m_scriptStateToId.begin(); it != m_scriptStateToId.end(); ++it) {
77        if (it->value == id)
78            return injectedScriptFor(it->key);
79    }
80
81    return InjectedScript();
82}
83
84int InjectedScriptManager::injectedScriptIdFor(ExecState* scriptState)
85{
86    auto it = m_scriptStateToId.find(scriptState);
87    if (it != m_scriptStateToId.end())
88        return it->value;
89
90    int id = m_nextInjectedScriptId++;
91    m_scriptStateToId.set(scriptState, id);
92    return id;
93}
94
95InjectedScript InjectedScriptManager::injectedScriptForObjectId(const String& objectId)
96{
97    RefPtr<InspectorValue> parsedObjectId = InspectorValue::parseJSON(objectId);
98    if (parsedObjectId && parsedObjectId->type() == InspectorValue::TypeObject) {
99        long injectedScriptId = 0;
100        bool success = parsedObjectId->asObject()->getNumber(ASCIILiteral("injectedScriptId"), &injectedScriptId);
101        if (success)
102            return m_idToInjectedScript.get(injectedScriptId);
103    }
104
105    return InjectedScript();
106}
107
108void InjectedScriptManager::discardInjectedScripts()
109{
110    m_injectedScriptHost->clearAllWrappers();
111    m_idToInjectedScript.clear();
112    m_scriptStateToId.clear();
113}
114
115void InjectedScriptManager::releaseObjectGroup(const String& objectGroup)
116{
117    for (auto it = m_idToInjectedScript.begin(); it != m_idToInjectedScript.end(); ++it)
118        it->value.releaseObjectGroup(objectGroup);
119}
120
121String InjectedScriptManager::injectedScriptSource()
122{
123    return String(reinterpret_cast<const char*>(InjectedScriptSource_js), sizeof(InjectedScriptSource_js));
124}
125
126Deprecated::ScriptObject InjectedScriptManager::createInjectedScript(const String& source, ExecState* scriptState, int id)
127{
128    JSLockHolder lock(scriptState);
129
130    SourceCode sourceCode = makeSource(source);
131    JSGlobalObject* globalObject = scriptState->lexicalGlobalObject();
132    JSValue globalThisValue = scriptState->globalThisValue();
133
134    JSValue evaluationException;
135    InspectorEvaluateHandler evaluateHandler = m_environment.evaluateHandler();
136    JSValue functionValue = evaluateHandler(scriptState, sourceCode, globalThisValue, &evaluationException);
137    if (evaluationException)
138        return Deprecated::ScriptObject();
139
140    CallData callData;
141    CallType callType = getCallData(functionValue, callData);
142    if (callType == CallTypeNone)
143        return Deprecated::ScriptObject();
144
145    MarkedArgumentBuffer args;
146    args.append(m_injectedScriptHost->jsWrapper(scriptState, globalObject));
147    args.append(globalThisValue);
148    args.append(jsNumber(id));
149
150    JSValue result = JSC::call(scriptState, functionValue, callType, callData, globalThisValue, args);
151    if (result.isObject())
152        return Deprecated::ScriptObject(scriptState, result.getObject());
153
154    return Deprecated::ScriptObject();
155}
156
157InjectedScript InjectedScriptManager::injectedScriptFor(ExecState* inspectedExecState)
158{
159    auto it = m_scriptStateToId.find(inspectedExecState);
160    if (it != m_scriptStateToId.end()) {
161        auto it1 = m_idToInjectedScript.find(it->value);
162        if (it1 != m_idToInjectedScript.end())
163            return it1->value;
164    }
165
166    if (!m_environment.canAccessInspectedScriptState(inspectedExecState))
167        return InjectedScript();
168
169    int id = injectedScriptIdFor(inspectedExecState);
170    Deprecated::ScriptObject injectedScriptObject = createInjectedScript(injectedScriptSource(), inspectedExecState, id);
171    InjectedScript result(injectedScriptObject, &m_environment);
172    m_idToInjectedScript.set(id, result);
173    didCreateInjectedScript(result);
174    return result;
175}
176
177void InjectedScriptManager::didCreateInjectedScript(InjectedScript)
178{
179    // Intentionally empty. This allows for subclasses to inject additional scripts.
180}
181
182} // namespace Inspector
183
184#endif // ENABLE(INSPECTOR)
185