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: 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) 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 108 PassOwnPtr<InspectorWorkerAgent> InspectorWorkerAgent::create() 109 { 110 return adoptPtr(new InspectorWorkerAgent()); 111 } 112 113 InspectorWorkerAgent::InspectorWorkerAgent() 114 : InspectorBaseAgent<InspectorWorkerAgent>("Worker") 115 , m_inspectorFrontend(0) 116 { 117 } 118 119 InspectorWorkerAgent::~InspectorWorkerAgent() 120 { 121 m_instrumentingAgents->setInspectorWorkerAgent(0); 122 } 123 124 void InspectorWorkerAgent::init() 125 { 126 m_instrumentingAgents->setInspectorWorkerAgent(this); 127 } 128 129 void InspectorWorkerAgent::setFrontend(InspectorFrontend* frontend) 130 { 131 m_inspectorFrontend = frontend; 132 } 133 134 void InspectorWorkerAgent::restore() 135 { 136 if (m_state->getBoolean(WorkerAgentState::workerInspectionEnabled)) 137 createWorkerFrontendChannelsForExistingWorkers(); 138 } 139 140 void InspectorWorkerAgent::clearFrontend() 141 { 142 m_state->setBoolean(WorkerAgentState::autoconnectToWorkers, false); 143 disable(0); 144 m_inspectorFrontend = 0; 145 } 146 147 void InspectorWorkerAgent::enable(ErrorString*) 148 { 149 m_state->setBoolean(WorkerAgentState::workerInspectionEnabled, true); 150 if (!m_inspectorFrontend) 151 return; 152 createWorkerFrontendChannelsForExistingWorkers(); 153 } 154 155 void InspectorWorkerAgent::disable(ErrorString*) 156 { 157 m_state->setBoolean(WorkerAgentState::workerInspectionEnabled, false); 158 if (!m_inspectorFrontend) 159 return; 160 destroyWorkerFrontendChannels(); 161 } 162 163 void InspectorWorkerAgent::canInspectWorkers(ErrorString*, bool* result) 164 { 165 *result = true; 166 } 167 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 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 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 195 void InspectorWorkerAgent::setAutoconnectToWorkers(ErrorString*, bool value) 196 { 197 m_state->setBoolean(WorkerAgentState::autoconnectToWorkers, value); 198 } 199 200 bool InspectorWorkerAgent::shouldPauseDedicatedWorkerOnStart() 201 { 202 return m_state->getBoolean(WorkerAgentState::autoconnectToWorkers); 203 } 204 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 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 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 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 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