diff options
8 files changed, 378 insertions, 68 deletions
diff --git a/chrome/browser/extensions/extension_debugger_api.cc b/chrome/browser/extensions/extension_debugger_api.cc index cd668dc..d5e3403 100644 --- a/chrome/browser/extensions/extension_debugger_api.cc +++ b/chrome/browser/extensions/extension_debugger_api.cc @@ -6,8 +6,10 @@ #include "chrome/browser/extensions/extension_debugger_api.h" +#include <map> #include <set> +#include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/memory/singleton.h" #include "base/string_number_conversions.h" @@ -39,7 +41,10 @@ class ExtensionDevToolsClientHost : public DevToolsClientHost, bool MatchesContentsAndExtensionId(TabContents* tab_contents, const std::string& extension_id); void Close(); - void SendMessageToBackend(const std::string& message); + void SendMessageToBackend(SendCommandDebuggerFunction* function, + const std::string& domain, + const std::string& command, + const Value& body); // DevToolsClientHost interface virtual void InspectedTabClosing(); @@ -58,6 +63,10 @@ class ExtensionDevToolsClientHost : public DevToolsClientHost, std::string extension_id_; int tab_id_; NotificationRegistrar registrar_; + int last_request_id_; + typedef std::map<int, scoped_refptr<SendCommandDebuggerFunction> > + PendingRequests; + PendingRequests pending_requests_; DISALLOW_COPY_AND_ASSIGN(ExtensionDevToolsClientHost); }; @@ -103,7 +112,8 @@ ExtensionDevToolsClientHost::ExtensionDevToolsClientHost( int tab_id) : tab_contents_(tab_contents), extension_id_(extension_id), - tab_id_(tab_id) { + tab_id_(tab_id), + last_request_id_(0) { AttachedClientHosts::GetInstance()->Add(this); // Detach from debugger when extension unloads. @@ -166,10 +176,23 @@ void ExtensionDevToolsClientHost::Close() { } void ExtensionDevToolsClientHost::SendMessageToBackend( - const std::string& message) { + SendCommandDebuggerFunction* function, + const std::string& domain, + const std::string& command, + const Value& body) { + DictionaryValue protocol_command; + int request_id = ++last_request_id_; + pending_requests_[request_id] = function; + protocol_command.SetInteger("id", request_id); + protocol_command.SetString("domain", domain); + protocol_command.SetString("command", command); + protocol_command.Set("arguments", body.DeepCopy()); + + std::string json_args; + base::JSONWriter::Write(&protocol_command, false, &json_args); DevToolsManager::GetInstance()->ForwardToDevToolsAgent( this, - DevToolsAgentMsg_DispatchOnInspectorBackend(message)); + DevToolsAgentMsg_DispatchOnInspectorBackend(json_args)); } void ExtensionDevToolsClientHost::Observe( @@ -183,14 +206,49 @@ void ExtensionDevToolsClientHost::Observe( void ExtensionDevToolsClientHost::OnDispatchOnInspectorFrontend( const std::string& data) { Profile* profile = tab_contents_->profile(); - if (profile != NULL && profile->GetExtensionEventRouter()) { - // data is stringified JSON object, while extension expects - // array of objects (tabId, data). - std::string message = StringPrintf("[%d,%s]", tab_id_, data.c_str()); + if (profile == NULL || !profile->GetExtensionEventRouter()) + return; + + scoped_ptr<Value> result(base::JSONReader::Read(data, false)); + if (!result->IsType(Value::TYPE_DICTIONARY)) + return; + DictionaryValue* dictionary = static_cast<DictionaryValue*>(result.get()); + std::string type; + if (dictionary->GetString("type", &type) && type == "event") { + std::string message = StringPrintf("[%d,%s]", tab_id_, data.c_str()); profile->GetExtensionEventRouter()->DispatchEventToExtension( - extension_id_, keys::kOnMessage, message, profile, GURL()); + extension_id_, keys::kOnEvent, message, profile, GURL()); + return; + } + + int request_id; + if (!dictionary->GetInteger("requestId", &request_id)) + return; + + SendCommandDebuggerFunction* function = pending_requests_[request_id]; + if (!function) + return; + + std::string error; + if (!dictionary->GetString("error", &error)) + error = ""; + + ListValue* protocol_errors; + if (dictionary->GetList("protocolErrors", &protocol_errors)) { + for (size_t i = 0; i < protocol_errors->GetSize(); ++i) { + std::string protocol_error; + if (protocol_errors->GetString(i, &protocol_error)) + error += "\n" + protocol_error; + } } + + Value* response_body; + if (!dictionary->Get("body", &response_body)) + response_body = NULL; + + function->SendResponseBody(response_body, error); + pending_requests_.erase(request_id); } DebuggerFunction::DebuggerFunction() @@ -254,6 +312,7 @@ bool AttachDebuggerFunction::RunImpl() { } new ExtensionDevToolsClientHost(contents_, GetExtension()->id(), tab_id); + SendResponse(true); return true; } @@ -269,25 +328,45 @@ bool DetachDebuggerFunction::RunImpl() { return false; client_host_->Close(); + SendResponse(true); return true; } -PostMessageDebuggerFunction::PostMessageDebuggerFunction() {} +SendCommandDebuggerFunction::SendCommandDebuggerFunction() {} -PostMessageDebuggerFunction::~PostMessageDebuggerFunction() {} +SendCommandDebuggerFunction::~SendCommandDebuggerFunction() {} -bool PostMessageDebuggerFunction::RunImpl() { +bool SendCommandDebuggerFunction::RunImpl() { int tab_id; EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id)); - Value *command; - EXTENSION_FUNCTION_VALIDATE(args_->Get(1, &command)); - if (!InitClientHost(tab_id)) return false; - std::string json_args; - base::JSONWriter::Write(command, false, &json_args); - client_host_->SendMessageToBackend(json_args); + std::string domain; + EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &domain)); + + std::string command; + EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &command)); + + Value *body; + EXTENSION_FUNCTION_VALIDATE(args_->Get(3, &body)); + + client_host_->SendMessageToBackend(this, domain, command, *body); return true; } + +void SendCommandDebuggerFunction::SendResponseBody(Value* body, + const std::string& error) { + if (!error.empty()) { + error_ = error; + SendResponse(false); + return; + } + + if (body) + result_.reset(body->DeepCopy()); + else + result_.reset(new DictionaryValue()); + SendResponse(true); +} diff --git a/chrome/browser/extensions/extension_debugger_api.h b/chrome/browser/extensions/extension_debugger_api.h index 9329476..963eb34 100644 --- a/chrome/browser/extensions/extension_debugger_api.h +++ b/chrome/browser/extensions/extension_debugger_api.h @@ -17,7 +17,7 @@ class ExtensionDevToolsClientHost; -class DebuggerFunction : public SyncExtensionFunction { +class DebuggerFunction : public AsyncExtensionFunction { protected: DebuggerFunction(); virtual ~DebuggerFunction() {} @@ -47,13 +47,16 @@ class DetachDebuggerFunction : public DebuggerFunction { DECLARE_EXTENSION_FUNCTION_NAME("experimental.debugger.detach") }; -// Implements the debugger.postMessage() extension function. -class PostMessageDebuggerFunction : public DebuggerFunction { +// Implements the debugger.sendCommand() extension function. +class SendCommandDebuggerFunction : public DebuggerFunction { public: - PostMessageDebuggerFunction(); - ~PostMessageDebuggerFunction(); + SendCommandDebuggerFunction(); + ~SendCommandDebuggerFunction(); virtual bool RunImpl(); - DECLARE_EXTENSION_FUNCTION_NAME("experimental.debugger.postMessage") + + void SendResponseBody(Value* body, + const std::string& error); + DECLARE_EXTENSION_FUNCTION_NAME("experimental.debugger.sendCommand") }; #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_DEBUGGER_API_H_ diff --git a/chrome/browser/extensions/extension_debugger_api_constants.cc b/chrome/browser/extensions/extension_debugger_api_constants.cc index 013857d..13cb2e1 100644 --- a/chrome/browser/extensions/extension_debugger_api_constants.cc +++ b/chrome/browser/extensions/extension_debugger_api_constants.cc @@ -10,7 +10,7 @@ const char kCommandKey[] = "command"; const char kDataKey[] = "data"; const char kTabIdKey[] = "tabId"; -const char kOnMessage[] = "experimental.debugger.onMessage"; +const char kOnEvent[] = "experimental.debugger.onEvent"; const char kOnDetach[] = "experimental.debugger.onDetach"; const char kAlreadyAttachedError[] = diff --git a/chrome/browser/extensions/extension_debugger_api_constants.h b/chrome/browser/extensions/extension_debugger_api_constants.h index c7d8224..5472700 100644 --- a/chrome/browser/extensions/extension_debugger_api_constants.h +++ b/chrome/browser/extensions/extension_debugger_api_constants.h @@ -16,7 +16,7 @@ extern const char kDataKey[]; extern const char kTabIdKey[]; // Events. -extern const char kOnMessage[]; +extern const char kOnEvent[]; extern const char kOnDetach[]; // Errors. diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc index 924a530..b0bd2bb 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.cc +++ b/chrome/browser/extensions/extension_function_dispatcher.cc @@ -319,7 +319,7 @@ void FactoryRegistry::ResetFunctions() { // Debugger RegisterFunction<AttachDebuggerFunction>(); RegisterFunction<DetachDebuggerFunction>(); - RegisterFunction<PostMessageDebuggerFunction>(); + RegisterFunction<SendCommandDebuggerFunction>(); } void FactoryRegistry::GetAllNames(std::vector<std::string>* names) { diff --git a/chrome/common/extensions/api/extension_api.json b/chrome/common/extensions/api/extension_api.json index 77be9dfc..1c2cc18 100644 --- a/chrome/common/extensions/api/extension_api.json +++ b/chrome/common/extensions/api/extension_api.json @@ -4819,49 +4819,68 @@ ] }, { - "name": "postMessage", + "name": "sendCommand", "type": "function", - "description": "Execute.", + "description": "Send given command to the debugger.", "parameters": [ { "type": "integer", "name": "tabId", - "description": "The id of the tab to which you want to send debugging message." + "description": "The id of the tab to which you want to send debugging command." + }, + { + "type": "string", + "name": "domain", + "description": "Debugging domain to send command in." + }, + { + "type": "string", + "name": "command", + "description": "Command name." }, { "type": "object", - "name": "request", + "name": "arguments", + "optional": true, "properties": {}, "additionalProperties": { "type": "any" }, - "description": "JSON object matching Developer Tools / Web Inspector Protocol request scheme." + "description": "JSON object matching Developer Tools / Web Inspector Protocol command scheme." }, { "type": "function", "name": "callback", "optional": true, - "parameters": [], - "description": "If an error occurs while posting the message, the callback will be called with no arguments and <a href='extension.html#property-lastError'>chrome.extension.lastError</a> will be set to the error message." + "parameters": [ + { + "type": "object", + "name": "result", + "properties": {}, + "additionalProperties": { "type": "any" }, + "description": "JSON object with the command response." + } + ], + "description": "Command response body. If an error occurs while posting the message, the callback will be called with no arguments and <a href='extension.html#property-lastError'>chrome.extension.lastError</a> will be set to the error message." } ] } ], "events": [ { - "name": "onMessage", + "name": "onEvent", "type": "function", - "description": "Fired when debugger wants to send response or event message to its client.", + "description": "Fired whenever debugger issues instrumentation event.", "parameters": [ { "type": "integer", "name": "tabId", - "description": "The id of the tab that generated debug message." + "description": "The id of the tab that generated debug evet." }, { "type": "object", "name": "message", "properties": {}, "additionalProperties": { "type": "any" }, - "description": "JSON object matching Developer Tools / Web Inspector Protocol response or event scheme." + "description": "JSON object matching Developer Tools / Web Inspector Protocol event scheme." } ] }, diff --git a/chrome/common/extensions/docs/experimental.debugger.html b/chrome/common/extensions/docs/experimental.debugger.html index 6784fb7..52fa031 100644 --- a/chrome/common/extensions/docs/experimental.debugger.html +++ b/chrome/common/extensions/docs/experimental.debugger.html @@ -284,7 +284,7 @@ </li><li> <a href="#method-detach">detach</a> </li><li> - <a href="#method-postMessage">postMessage</a> + <a href="#method-sendCommand">sendCommand</a> </li> </ol> </li> @@ -294,7 +294,7 @@ <li> <a href="#event-onDetach">onDetach</a> </li><li> - <a href="#event-onMessage">onMessage</a> + <a href="#event-onEvent">onEvent</a> </li> </ol> </li> @@ -770,19 +770,21 @@ terminated. Extension can then re-establish it via attaching to a tab later. </div> <!-- /description --> </div><div class="apiItem"> - <a name="method-postMessage"></a> <!-- method-anchor --> - <h4>postMessage</h4> + <a name="method-sendCommand"></a> <!-- method-anchor --> + <h4>sendCommand</h4> <div class="summary"><span style="display: none; ">void</span> <!-- Note: intentionally longer 80 columns --> - <span>chrome.experimental.debugger.postMessage</span>(<span class="null"><span style="display: none; ">, </span><span>integer</span> - <var><span>tabId</span></var></span><span class="null"><span>, </span><span>object</span> - <var><span>request</span></var></span><span class="optional"><span>, </span><span>function</span> + <span>chrome.experimental.debugger.sendCommand</span>(<span class="null"><span style="display: none; ">, </span><span>integer</span> + <var><span>tabId</span></var></span><span class="null"><span>, </span><span>string</span> + <var><span>domain</span></var></span><span class="null"><span>, </span><span>string</span> + <var><span>command</span></var></span><span class="optional"><span>, </span><span>object</span> + <var><span>arguments</span></var></span><span class="optional"><span>, </span><span>function</span> <var><span>callback</span></var></span>)</div> <div class="description"> <p class="todo" style="display: none; ">Undocumented.</p> - <p>Execute.</p> + <p>Send given command to the debugger.</p> <!-- PARAMETERS --> <h4>Parameters</h4> @@ -818,7 +820,7 @@ terminated. Extension can then re-establish it via attaching to a tab later. <dd class="todo" style="display: none; "> Undocumented. </dd> - <dd>The id of the tab to which you want to send debugging message.</dd> + <dd>The id of the tab to which you want to send debugging command.</dd> <dd style="display: none; "> This parameter was added in version <b><span></span></b>. @@ -858,7 +860,7 @@ terminated. Extension can then re-establish it via attaching to a tab later. </div><div> <div> <dt> - <var>request</var> + <var>domain</var> <em> <!-- TYPE --> @@ -874,6 +876,142 @@ terminated. Extension can then re-establish it via attaching to a tab later. <span style="display: none; "> array of <span><span></span></span> </span> + <span>string</span> + <span style="display: none; "></span> + </span> + </span> + ) + </div> + + </em> + </dt> + <dd class="todo" style="display: none; "> + Undocumented. + </dd> + <dd>Debugging domain to send command in.</dd> + <dd style="display: none; "> + This parameter was added in version + <b><span></span></b>. + You must omit this parameter in earlier versions, + and you may omit it in any version. If you require this + parameter, the manifest key + <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a> + can ensure that your extension won't be run in an earlier browser version. + </dd> + + <!-- OBJECT PROPERTIES --> + <dd style="display: none; "> + <dl> + <div> + <div> + </div> + </div> + </dl> + </dd> + + <!-- OBJECT METHODS --> + <dd style="display: none; "> + <div></div> + </dd> + + <!-- OBJECT EVENT FIELDS --> + <dd style="display: none; "> + <div></div> + </dd> + + <!-- FUNCTION PARAMETERS --> + <dd style="display: none; "> + <div></div> + </dd> + + </div> + </div><div> + <div> + <dt> + <var>command</var> + <em> + + <!-- TYPE --> + <div style="display:inline"> + ( + <span class="optional" style="display: none; ">optional</span> + <span class="enum" style="display: none; ">enumerated</span> + <span id="typeTemplate"> + <span style="display: none; "> + <a> Type</a> + </span> + <span> + <span style="display: none; "> + array of <span><span></span></span> + </span> + <span>string</span> + <span style="display: none; "></span> + </span> + </span> + ) + </div> + + </em> + </dt> + <dd class="todo" style="display: none; "> + Undocumented. + </dd> + <dd>Command name.</dd> + <dd style="display: none; "> + This parameter was added in version + <b><span></span></b>. + You must omit this parameter in earlier versions, + and you may omit it in any version. If you require this + parameter, the manifest key + <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a> + can ensure that your extension won't be run in an earlier browser version. + </dd> + + <!-- OBJECT PROPERTIES --> + <dd style="display: none; "> + <dl> + <div> + <div> + </div> + </div> + </dl> + </dd> + + <!-- OBJECT METHODS --> + <dd style="display: none; "> + <div></div> + </dd> + + <!-- OBJECT EVENT FIELDS --> + <dd style="display: none; "> + <div></div> + </dd> + + <!-- FUNCTION PARAMETERS --> + <dd style="display: none; "> + <div></div> + </dd> + + </div> + </div><div> + <div> + <dt> + <var>arguments</var> + <em> + + <!-- TYPE --> + <div style="display:inline"> + ( + <span class="optional">optional</span> + <span class="enum" style="display: none; ">enumerated</span> + <span id="typeTemplate"> + <span style="display: none; "> + <a> Type</a> + </span> + <span> + <span style="display: none; "> + array of <span><span></span></span> + </span> <span>object</span> <span style="display: none; "></span> </span> @@ -886,7 +1024,7 @@ terminated. Extension can then re-establish it via attaching to a tab later. <dd class="todo" style="display: none; "> Undocumented. </dd> - <dd>JSON object matching Developer Tools / Web Inspector Protocol request scheme.</dd> + <dd>JSON object matching Developer Tools / Web Inspector Protocol command scheme.</dd> <dd style="display: none; "> This parameter was added in version <b><span></span></b>. @@ -954,7 +1092,7 @@ terminated. Extension can then re-establish it via attaching to a tab later. <dd class="todo" style="display: none; "> Undocumented. </dd> - <dd>If an error occurs while posting the message, the callback will be called with no arguments and <a href="extension.html#property-lastError">chrome.extension.lastError</a> will be set to the error message.</dd> + <dd>Command response body. If an error occurs while posting the message, the callback will be called with no arguments and <a href="extension.html#property-lastError">chrome.extension.lastError</a> will be set to the error message.</dd> <dd style="display: none; "> This parameter was added in version <b><span></span></b>. @@ -1017,11 +1155,76 @@ terminated. Extension can then re-establish it via attaching to a tab later. </p> <!-- Note: intentionally longer 80 columns --> - <pre>function(<span></span>) <span class="subdued">{...}</span>;</pre> + <pre>function(<span>object result</span>) <span class="subdued">{...}</span>;</pre> <dl> - <div style="display: none; "> + <div> <div> - </div> + <dt> + <var>result</var> + <em> + + <!-- TYPE --> + <div style="display:inline"> + ( + <span class="optional" style="display: none; ">optional</span> + <span class="enum" style="display: none; ">enumerated</span> + <span id="typeTemplate"> + <span style="display: none; "> + <a> Type</a> + </span> + <span> + <span style="display: none; "> + array of <span><span></span></span> + </span> + <span>object</span> + <span style="display: none; "></span> + </span> + </span> + ) + </div> + + </em> + </dt> + <dd class="todo" style="display: none; "> + Undocumented. + </dd> + <dd>JSON object with the command response.</dd> + <dd style="display: none; "> + This parameter was added in version + <b><span></span></b>. + You must omit this parameter in earlier versions, + and you may omit it in any version. If you require this + parameter, the manifest key + <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a> + can ensure that your extension won't be run in an earlier browser version. + </dd> + + <!-- OBJECT PROPERTIES --> + <dd> + <dl> + <div style="display: none; "> + <div> + </div> + </div> + </dl> + </dd> + + <!-- OBJECT METHODS --> + <dd style="display: none; "> + <div></div> + </dd> + + <!-- OBJECT EVENT FIELDS --> + <dd style="display: none; "> + <div></div> + </dd> + + <!-- FUNCTION PARAMETERS --> + <dd style="display: none; "> + <div></div> + </dd> + + </div> </div> </dl> </div> @@ -1136,17 +1339,17 @@ terminated. Extension can then re-establish it via attaching to a tab later. </div> <!-- /decription --> </div><div class="apiItem"> - <a name="event-onMessage"></a> - <h4>onMessage</h4> + <a name="event-onEvent"></a> + <h4>onEvent</h4> <div class="summary"> <!-- Note: intentionally longer 80 columns --> - <span class="subdued">chrome.experimental.debugger.</span><span>onMessage</span><span class="subdued">.addListener</span>(function(<span>integer tabId, object message</span>) <span class="subdued">{...}</span>); + <span class="subdued">chrome.experimental.debugger.</span><span>onEvent</span><span class="subdued">.addListener</span>(function(<span>integer tabId, object message</span>) <span class="subdued">{...}</span>); </div> <div class="description"> <p class="todo" style="display: none; ">Undocumented.</p> - <p>Fired when debugger wants to send response or event message to its client.</p> + <p>Fired whenever debugger issues instrumentation event.</p> <!-- PARAMETERS --> <div> @@ -1183,7 +1386,7 @@ terminated. Extension can then re-establish it via attaching to a tab later. <dd class="todo" style="display: none; "> Undocumented. </dd> - <dd>The id of the tab that generated debug message.</dd> + <dd>The id of the tab that generated debug evet.</dd> <dd style="display: none; "> This parameter was added in version <b><span></span></b>. @@ -1251,7 +1454,7 @@ terminated. Extension can then re-establish it via attaching to a tab later. <dd class="todo" style="display: none; "> Undocumented. </dd> - <dd>JSON object matching Developer Tools / Web Inspector Protocol response or event scheme.</dd> + <dd>JSON object matching Developer Tools / Web Inspector Protocol event scheme.</dd> <dd style="display: none; "> This parameter was added in version <b><span></span></b>. diff --git a/chrome/test/data/extensions/api_test/debugger/background.html b/chrome/test/data/extensions/api_test/debugger/background.html index b618f7f..09a5271 100644 --- a/chrome/test/data/extensions/api_test/debugger/background.html +++ b/chrome/test/data/extensions/api_test/debugger/background.html @@ -20,22 +20,28 @@ chrome.test.runTests([ tabId + ".")); }, - function postMessage() { - function onMessage(messageTabId) { - chrome.test.assertEq(tabId, messageTabId); - chrome.experimental.debugger.onMessage.removeListener(onMessage); - chrome.test.succeed(); + function sendCommand() { + function onResponse() { + if (chrome.extension.lastError && chrome.extension.lastError.message.indexOf("InvalidDomain") != -1) + chrome.test.succeed(); + else + chrome.test.fail(); } - chrome.experimental.debugger.onMessage.addListener(onMessage); - chrome.experimental.debugger.postMessage(tabId, {}); + + chrome.experimental.debugger.sendCommand( + tabId, + "InvalidDomain", + "invalidCommand", + {}, + onResponse); }, function detach() { chrome.experimental.debugger.detach(tabId, pass()); }, - function postMessageAfterDetach() { - chrome.experimental.debugger.postMessage(tabId, {}, + function sendCommandAfterDetach() { + chrome.experimental.debugger.sendCommand(tabId, "Foo", "bar", {}, fail("Debugger is not attached to the tab with id: " + tabId + ".")); }, |