1 /*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32
33 #include "core/inspector/InspectorWorkerAgent.h"
34
35 #include "core/InspectorFrontend.h"
36 #include "core/inspector/InspectorState.h"
37 #include "core/inspector/InstrumentingAgents.h"
38 #include "core/inspector/JSONParser.h"
39 #include "core/workers/WorkerGlobalScopeProxy.h"
40 #include "platform/JSONValues.h"
41 #include "platform/weborigin/KURL.h"
42 #include "wtf/PassOwnPtr.h"
43 #include "wtf/RefPtr.h"
44
45 namespace WebCore {
46
47 namespace WorkerAgentState {
48 static const char workerInspectionEnabled[] = "workerInspectionEnabled";
49 static const char autoconnectToWorkers[] = "autoconnectToWorkers";
50 };
51
52 class InspectorWorkerAgent::WorkerFrontendChannel FINAL : public WorkerGlobalScopeProxy::PageInspector {
53 WTF_MAKE_FAST_ALLOCATED;
54 public:
WorkerFrontendChannel(InspectorFrontend * frontend,WorkerGlobalScopeProxy * proxy)55 explicit WorkerFrontendChannel(InspectorFrontend* frontend, WorkerGlobalScopeProxy* proxy)
56 : m_frontend(frontend)
57 , m_proxy(proxy)
58 , m_id(s_nextId++)
59 , m_connected(false)
60 {
61 }
~WorkerFrontendChannel()62 virtual ~WorkerFrontendChannel()
63 {
64 disconnectFromWorkerGlobalScope();
65 }
66
id() const67 int id() const { return m_id; }
proxy() const68 WorkerGlobalScopeProxy* proxy() const { return m_proxy; }
69
connectToWorkerGlobalScope()70 void connectToWorkerGlobalScope()
71 {
72 if (m_connected)
73 return;
74 m_connected = true;
75 m_proxy->connectToInspector(this);
76 }
77
disconnectFromWorkerGlobalScope()78 void disconnectFromWorkerGlobalScope()
79 {
80 if (!m_connected)
81 return;
82 m_connected = false;
83 m_proxy->disconnectFromInspector();
84 }
85
86 private:
87 // WorkerGlobalScopeProxy::PageInspector implementation
dispatchMessageFromWorker(const String & message)88 virtual void dispatchMessageFromWorker(const String& message) OVERRIDE
89 {
90 RefPtr<JSONValue> value = parseJSON(message);
91 if (!value)
92 return;
93 RefPtr<JSONObject> messageObject = value->asObject();
94 if (!messageObject)
95 return;
96 m_frontend->worker()->dispatchMessageFromWorker(m_id, messageObject);
97 }
98
99 InspectorFrontend* m_frontend;
100 WorkerGlobalScopeProxy* m_proxy;
101 int m_id;
102 bool m_connected;
103 static int s_nextId;
104 };
105
106 int InspectorWorkerAgent::WorkerFrontendChannel::s_nextId = 1;
107
create()108 PassOwnPtr<InspectorWorkerAgent> InspectorWorkerAgent::create()
109 {
110 return adoptPtr(new InspectorWorkerAgent());
111 }
112
InspectorWorkerAgent()113 InspectorWorkerAgent::InspectorWorkerAgent()
114 : InspectorBaseAgent<InspectorWorkerAgent>("Worker")
115 , m_inspectorFrontend(0)
116 {
117 }
118
~InspectorWorkerAgent()119 InspectorWorkerAgent::~InspectorWorkerAgent()
120 {
121 m_instrumentingAgents->setInspectorWorkerAgent(0);
122 }
123
init()124 void InspectorWorkerAgent::init()
125 {
126 m_instrumentingAgents->setInspectorWorkerAgent(this);
127 }
128
setFrontend(InspectorFrontend * frontend)129 void InspectorWorkerAgent::setFrontend(InspectorFrontend* frontend)
130 {
131 m_inspectorFrontend = frontend;
132 }
133
restore()134 void InspectorWorkerAgent::restore()
135 {
136 if (m_state->getBoolean(WorkerAgentState::workerInspectionEnabled))
137 createWorkerFrontendChannelsForExistingWorkers();
138 }
139
clearFrontend()140 void InspectorWorkerAgent::clearFrontend()
141 {
142 m_state->setBoolean(WorkerAgentState::autoconnectToWorkers, false);
143 disable(0);
144 m_inspectorFrontend = 0;
145 }
146
enable(ErrorString *)147 void InspectorWorkerAgent::enable(ErrorString*)
148 {
149 m_state->setBoolean(WorkerAgentState::workerInspectionEnabled, true);
150 if (!m_inspectorFrontend)
151 return;
152 createWorkerFrontendChannelsForExistingWorkers();
153 }
154
disable(ErrorString *)155 void InspectorWorkerAgent::disable(ErrorString*)
156 {
157 m_state->setBoolean(WorkerAgentState::workerInspectionEnabled, false);
158 if (!m_inspectorFrontend)
159 return;
160 destroyWorkerFrontendChannels();
161 }
162
canInspectWorkers(ErrorString *,bool * result)163 void InspectorWorkerAgent::canInspectWorkers(ErrorString*, bool* result)
164 {
165 *result = true;
166 }
167
connectToWorker(ErrorString * error,int workerId)168 void InspectorWorkerAgent::connectToWorker(ErrorString* error, int workerId)
169 {
170 WorkerFrontendChannel* channel = m_idToChannel.get(workerId);
171 if (channel)
172 channel->connectToWorkerGlobalScope();
173 else
174 *error = "Worker is gone";
175 }
176
disconnectFromWorker(ErrorString * error,int workerId)177 void InspectorWorkerAgent::disconnectFromWorker(ErrorString* error, int workerId)
178 {
179 WorkerFrontendChannel* channel = m_idToChannel.get(workerId);
180 if (channel)
181 channel->disconnectFromWorkerGlobalScope();
182 else
183 *error = "Worker is gone";
184 }
185
sendMessageToWorker(ErrorString * error,int workerId,const RefPtr<JSONObject> & message)186 void InspectorWorkerAgent::sendMessageToWorker(ErrorString* error, int workerId, const RefPtr<JSONObject>& message)
187 {
188 WorkerFrontendChannel* channel = m_idToChannel.get(workerId);
189 if (channel)
190 channel->proxy()->sendMessageToInspector(message->toJSONString());
191 else
192 *error = "Worker is gone";
193 }
194
setAutoconnectToWorkers(ErrorString *,bool value)195 void InspectorWorkerAgent::setAutoconnectToWorkers(ErrorString*, bool value)
196 {
197 m_state->setBoolean(WorkerAgentState::autoconnectToWorkers, value);
198 }
199
shouldPauseDedicatedWorkerOnStart()200 bool InspectorWorkerAgent::shouldPauseDedicatedWorkerOnStart()
201 {
202 return m_state->getBoolean(WorkerAgentState::autoconnectToWorkers);
203 }
204
didStartWorkerGlobalScope(WorkerGlobalScopeProxy * workerGlobalScopeProxy,const KURL & url)205 void InspectorWorkerAgent::didStartWorkerGlobalScope(WorkerGlobalScopeProxy* workerGlobalScopeProxy, const KURL& url)
206 {
207 m_dedicatedWorkers.set(workerGlobalScopeProxy, url.string());
208 if (m_inspectorFrontend && m_state->getBoolean(WorkerAgentState::workerInspectionEnabled))
209 createWorkerFrontendChannel(workerGlobalScopeProxy, url.string());
210 }
211
workerGlobalScopeTerminated(WorkerGlobalScopeProxy * proxy)212 void InspectorWorkerAgent::workerGlobalScopeTerminated(WorkerGlobalScopeProxy* proxy)
213 {
214 m_dedicatedWorkers.remove(proxy);
215 for (WorkerChannels::iterator it = m_idToChannel.begin(); it != m_idToChannel.end(); ++it) {
216 if (proxy == it->value->proxy()) {
217 m_inspectorFrontend->worker()->workerTerminated(it->key);
218 delete it->value;
219 m_idToChannel.remove(it);
220 return;
221 }
222 }
223 }
224
createWorkerFrontendChannelsForExistingWorkers()225 void InspectorWorkerAgent::createWorkerFrontendChannelsForExistingWorkers()
226 {
227 for (DedicatedWorkers::iterator it = m_dedicatedWorkers.begin(); it != m_dedicatedWorkers.end(); ++it)
228 createWorkerFrontendChannel(it->key, it->value);
229 }
230
destroyWorkerFrontendChannels()231 void InspectorWorkerAgent::destroyWorkerFrontendChannels()
232 {
233 for (WorkerChannels::iterator it = m_idToChannel.begin(); it != m_idToChannel.end(); ++it) {
234 it->value->disconnectFromWorkerGlobalScope();
235 delete it->value;
236 }
237 m_idToChannel.clear();
238 }
239
createWorkerFrontendChannel(WorkerGlobalScopeProxy * workerGlobalScopeProxy,const String & url)240 void InspectorWorkerAgent::createWorkerFrontendChannel(WorkerGlobalScopeProxy* workerGlobalScopeProxy, const String& url)
241 {
242 WorkerFrontendChannel* channel = new WorkerFrontendChannel(m_inspectorFrontend, workerGlobalScopeProxy);
243 m_idToChannel.set(channel->id(), channel);
244
245 ASSERT(m_inspectorFrontend);
246 bool autoconnectToWorkers = m_state->getBoolean(WorkerAgentState::autoconnectToWorkers);
247 if (autoconnectToWorkers)
248 channel->connectToWorkerGlobalScope();
249 m_inspectorFrontend->worker()->workerCreated(channel->id(), url, autoconnectToWorkers);
250 }
251
252 } // namespace WebCore
253