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 "InspectorFrontend.h" 36 #include "core/inspector/InspectorState.h" 37 #include "core/inspector/InstrumentingAgents.h" 38 #include "core/inspector/JSONParser.h" 39 #include "core/platform/JSONValues.h" 40 #include "core/workers/WorkerGlobalScopeProxy.h" 41 #include "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 : public WorkerGlobalScopeProxy::PageInspector { 53 WTF_MAKE_FAST_ALLOCATED; 54 public: 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 } 62 virtual ~WorkerFrontendChannel() 63 { 64 disconnectFromWorkerGlobalScope(); 65 } 66 67 int id() const { return m_id; } 68 WorkerGlobalScopeProxy* proxy() const { return m_proxy; } 69 70 void connectToWorkerGlobalScope() 71 { 72 if (m_connected) 73 return; 74 m_connected = true; 75 m_proxy->connectToInspector(this); 76 } 77 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 88 virtual void dispatchMessageFromWorker(const String& message) 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 108 PassOwnPtr<InspectorWorkerAgent> InspectorWorkerAgent::create(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState) 109 { 110 return adoptPtr(new InspectorWorkerAgent(instrumentingAgents, inspectorState)); 111 } 112 113 InspectorWorkerAgent::InspectorWorkerAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState) 114 : InspectorBaseAgent<InspectorWorkerAgent>("Worker", instrumentingAgents, inspectorState) 115 , m_inspectorFrontend(0) 116 { 117 m_instrumentingAgents->setInspectorWorkerAgent(this); 118 } 119 120 InspectorWorkerAgent::~InspectorWorkerAgent() 121 { 122 m_instrumentingAgents->setInspectorWorkerAgent(0); 123 } 124 125 void InspectorWorkerAgent::setFrontend(InspectorFrontend* frontend) 126 { 127 m_inspectorFrontend = frontend; 128 } 129 130 void InspectorWorkerAgent::restore() 131 { 132 if (m_state->getBoolean(WorkerAgentState::workerInspectionEnabled)) 133 createWorkerFrontendChannelsForExistingWorkers(); 134 } 135 136 void InspectorWorkerAgent::clearFrontend() 137 { 138 m_state->setBoolean(WorkerAgentState::autoconnectToWorkers, false); 139 disable(0); 140 m_inspectorFrontend = 0; 141 } 142 143 void InspectorWorkerAgent::enable(ErrorString*) 144 { 145 m_state->setBoolean(WorkerAgentState::workerInspectionEnabled, true); 146 if (!m_inspectorFrontend) 147 return; 148 createWorkerFrontendChannelsForExistingWorkers(); 149 } 150 151 void InspectorWorkerAgent::disable(ErrorString*) 152 { 153 m_state->setBoolean(WorkerAgentState::workerInspectionEnabled, false); 154 if (!m_inspectorFrontend) 155 return; 156 destroyWorkerFrontendChannels(); 157 } 158 159 void InspectorWorkerAgent::canInspectWorkers(ErrorString*, bool* result) 160 { 161 *result = true; 162 } 163 164 void InspectorWorkerAgent::connectToWorker(ErrorString* error, int workerId) 165 { 166 WorkerFrontendChannel* channel = m_idToChannel.get(workerId); 167 if (channel) 168 channel->connectToWorkerGlobalScope(); 169 else 170 *error = "Worker is gone"; 171 } 172 173 void InspectorWorkerAgent::disconnectFromWorker(ErrorString* error, int workerId) 174 { 175 WorkerFrontendChannel* channel = m_idToChannel.get(workerId); 176 if (channel) 177 channel->disconnectFromWorkerGlobalScope(); 178 else 179 *error = "Worker is gone"; 180 } 181 182 void InspectorWorkerAgent::sendMessageToWorker(ErrorString* error, int workerId, const RefPtr<JSONObject>& message) 183 { 184 WorkerFrontendChannel* channel = m_idToChannel.get(workerId); 185 if (channel) 186 channel->proxy()->sendMessageToInspector(message->toJSONString()); 187 else 188 *error = "Worker is gone"; 189 } 190 191 void InspectorWorkerAgent::setAutoconnectToWorkers(ErrorString*, bool value) 192 { 193 m_state->setBoolean(WorkerAgentState::autoconnectToWorkers, value); 194 } 195 196 bool InspectorWorkerAgent::shouldPauseDedicatedWorkerOnStart() 197 { 198 return m_state->getBoolean(WorkerAgentState::autoconnectToWorkers); 199 } 200 201 void InspectorWorkerAgent::didStartWorkerGlobalScope(WorkerGlobalScopeProxy* workerGlobalScopeProxy, const KURL& url) 202 { 203 m_dedicatedWorkers.set(workerGlobalScopeProxy, url.string()); 204 if (m_inspectorFrontend && m_state->getBoolean(WorkerAgentState::workerInspectionEnabled)) 205 createWorkerFrontendChannel(workerGlobalScopeProxy, url.string()); 206 } 207 208 void InspectorWorkerAgent::workerGlobalScopeTerminated(WorkerGlobalScopeProxy* proxy) 209 { 210 m_dedicatedWorkers.remove(proxy); 211 for (WorkerChannels::iterator it = m_idToChannel.begin(); it != m_idToChannel.end(); ++it) { 212 if (proxy == it->value->proxy()) { 213 m_inspectorFrontend->worker()->workerTerminated(it->key); 214 delete it->value; 215 m_idToChannel.remove(it); 216 return; 217 } 218 } 219 } 220 221 void InspectorWorkerAgent::createWorkerFrontendChannelsForExistingWorkers() 222 { 223 for (DedicatedWorkers::iterator it = m_dedicatedWorkers.begin(); it != m_dedicatedWorkers.end(); ++it) 224 createWorkerFrontendChannel(it->key, it->value); 225 } 226 227 void InspectorWorkerAgent::destroyWorkerFrontendChannels() 228 { 229 for (WorkerChannels::iterator it = m_idToChannel.begin(); it != m_idToChannel.end(); ++it) { 230 it->value->disconnectFromWorkerGlobalScope(); 231 delete it->value; 232 } 233 m_idToChannel.clear(); 234 } 235 236 void InspectorWorkerAgent::createWorkerFrontendChannel(WorkerGlobalScopeProxy* workerGlobalScopeProxy, const String& url) 237 { 238 WorkerFrontendChannel* channel = new WorkerFrontendChannel(m_inspectorFrontend, workerGlobalScopeProxy); 239 m_idToChannel.set(channel->id(), channel); 240 241 ASSERT(m_inspectorFrontend); 242 bool autoconnectToWorkers = m_state->getBoolean(WorkerAgentState::autoconnectToWorkers); 243 if (autoconnectToWorkers) 244 channel->connectToWorkerGlobalScope(); 245 m_inspectorFrontend->worker()->workerCreated(channel->id(), url, autoconnectToWorkers); 246 } 247 248 } // namespace WebCore 249