]> git.saurik.com Git - apple/javascriptcore.git/blame - inspector/InspectorBackendDispatcher.cpp
JavaScriptCore-7600.1.4.13.1.tar.gz
[apple/javascriptcore.git] / inspector / InspectorBackendDispatcher.cpp
CommitLineData
81345200
A
1/*
2 * Copyright (C) 2013 Apple Inc. All Rights Reserved.
3 * Copyright (C) 2011 The Chromium Authors. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "InspectorBackendDispatcher.h"
29
30#if ENABLE(INSPECTOR)
31
32#include "InspectorFrontendChannel.h"
33#include "InspectorValues.h"
34#include <wtf/text/CString.h>
35#include <wtf/text/WTFString.h>
36
37namespace Inspector {
38
39InspectorBackendDispatcher::CallbackBase::CallbackBase(PassRefPtr<InspectorBackendDispatcher> backendDispatcher, int id)
40 : m_backendDispatcher(backendDispatcher)
41 , m_id(id)
42 , m_alreadySent(false)
43{
44}
45
46bool InspectorBackendDispatcher::CallbackBase::isActive() const
47{
48 return !m_alreadySent && m_backendDispatcher->isActive();
49}
50
51void InspectorBackendDispatcher::CallbackBase::sendFailure(const ErrorString& error)
52{
53 ASSERT(error.length());
54 sendIfActive(nullptr, error);
55}
56
57void InspectorBackendDispatcher::CallbackBase::sendIfActive(PassRefPtr<InspectorObject> partialMessage, const ErrorString& invocationError)
58{
59 if (m_alreadySent)
60 return;
61
62 m_backendDispatcher->sendResponse(m_id, partialMessage, invocationError);
63 m_alreadySent = true;
64}
65
66PassRefPtr<InspectorBackendDispatcher> InspectorBackendDispatcher::create(InspectorFrontendChannel* inspectorFrontendChannel)
67{
68 return adoptRef(new InspectorBackendDispatcher(inspectorFrontendChannel));
69}
70
71void InspectorBackendDispatcher::registerDispatcherForDomain(const String& domain, InspectorSupplementalBackendDispatcher* dispatcher)
72{
73 auto result = m_dispatchers.add(domain, dispatcher);
74 ASSERT_UNUSED(result, result.isNewEntry);
75}
76
77void InspectorBackendDispatcher::dispatch(const String& message)
78{
79 Ref<InspectorBackendDispatcher> protect(*this);
80
81 RefPtr<InspectorValue> parsedMessage = InspectorValue::parseJSON(message);
82 if (!parsedMessage) {
83 reportProtocolError(nullptr, ParseError, ASCIILiteral("Message must be in JSON format"));
84 return;
85 }
86
87 RefPtr<InspectorObject> messageObject = parsedMessage->asObject();
88 if (!messageObject) {
89 reportProtocolError(nullptr, InvalidRequest, ASCIILiteral("Message must be a JSONified object"));
90 return;
91 }
92
93 RefPtr<InspectorValue> callIdValue = messageObject->get("id");
94 if (!callIdValue) {
95 reportProtocolError(nullptr, InvalidRequest, ASCIILiteral("'id' property was not found"));
96 return;
97 }
98
99 long callId = 0;
100 if (!callIdValue->asNumber(&callId)) {
101 reportProtocolError(nullptr, InvalidRequest, ASCIILiteral("The type of 'id' property must be number"));
102 return;
103 }
104
105 RefPtr<InspectorValue> methodValue = messageObject->get("method");
106 if (!methodValue) {
107 reportProtocolError(&callId, InvalidRequest, ASCIILiteral("'method' property wasn't found"));
108 return;
109 }
110
111 String method;
112 if (!methodValue->asString(&method)) {
113 reportProtocolError(&callId, InvalidRequest, ASCIILiteral("The type of 'method' property must be string"));
114 return;
115 }
116
117 size_t position = method.find('.');
118 if (position == WTF::notFound) {
119 reportProtocolError(&callId, InvalidRequest, ASCIILiteral("The 'method' property was formatted incorrectly. It should be 'Domain.method'"));
120 return;
121 }
122
123 String domain = method.substring(0, position);
124 InspectorSupplementalBackendDispatcher* domainDispatcher = m_dispatchers.get(domain);
125 if (!domainDispatcher) {
126 reportProtocolError(&callId, MethodNotFound, "'" + domain + "' domain was not found");
127 return;
128 }
129
130 String domainMethod = method.substring(position + 1);
131 domainDispatcher->dispatch(callId, domainMethod, messageObject.release());
132}
133
134void InspectorBackendDispatcher::sendResponse(long callId, PassRefPtr<InspectorObject> result, const ErrorString& invocationError)
135{
136 if (!m_inspectorFrontendChannel)
137 return;
138
139 if (invocationError.length()) {
140 reportProtocolError(&callId, ServerError, invocationError);
141 return;
142 }
143
144 RefPtr<InspectorObject> responseMessage = InspectorObject::create();
145 responseMessage->setObject(ASCIILiteral("result"), result);
146 responseMessage->setNumber(ASCIILiteral("id"), callId);
147 m_inspectorFrontendChannel->sendMessageToFrontend(responseMessage->toJSONString());
148}
149
150void InspectorBackendDispatcher::reportProtocolError(const long* const callId, CommonErrorCode errorCode, const String& errorMessage) const
151{
152 reportProtocolError(callId, errorCode, errorMessage, nullptr);
153}
154
155void InspectorBackendDispatcher::reportProtocolError(const long* const callId, CommonErrorCode errorCode, const String& errorMessage, PassRefPtr<InspectorArray> data) const
156{
157 static const int errorCodes[] = {
158 -32700, // ParseError
159 -32600, // InvalidRequest
160 -32601, // MethodNotFound
161 -32602, // InvalidParams
162 -32603, // InternalError
163 -32000, // ServerError
164 };
165
166 ASSERT(errorCode >= 0);
167 ASSERT((unsigned)errorCode < WTF_ARRAY_LENGTH(errorCodes));
168 ASSERT(errorCodes[errorCode]);
169
170 if (!m_inspectorFrontendChannel)
171 return;
172
173 RefPtr<InspectorObject> error = InspectorObject::create();
174 error->setNumber(ASCIILiteral("code"), errorCodes[errorCode]);
175 error->setString(ASCIILiteral("message"), errorMessage);
176 if (data)
177 error->setArray(ASCIILiteral("data"), data);
178
179 RefPtr<InspectorObject> message = InspectorObject::create();
180 message->setObject(ASCIILiteral("error"), error.release());
181 if (callId)
182 message->setNumber(ASCIILiteral("id"), *callId);
183 else
184 message->setValue(ASCIILiteral("id"), InspectorValue::null());
185
186 m_inspectorFrontendChannel->sendMessageToFrontend(message->toJSONString());
187}
188
189template<typename ReturnValueType, typename ValueType, typename DefaultValueType>
190static ReturnValueType getPropertyValue(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors, DefaultValueType defaultValue, bool (*asMethod)(InspectorValue*, ValueType*), const char* typeName)
191{
192 ASSERT(protocolErrors);
193
194 ValueType value = defaultValue;
195 if (valueFound)
196 *valueFound = false;
197
198 if (!object) {
199 if (!valueFound)
200 protocolErrors->pushString(String::format("'params' object must contain required parameter '%s' with type '%s'.", name.utf8().data(), typeName));
201 return value;
202 }
203
204 InspectorObject::const_iterator end = object->end();
205 InspectorObject::const_iterator valueIterator = object->find(name);
206 if (valueIterator == end) {
207 if (!valueFound)
208 protocolErrors->pushString(String::format("Parameter '%s' with type '%s' was not found.", name.utf8().data(), typeName));
209 return value;
210 }
211
212 if (!asMethod(valueIterator->value.get(), &value)) {
213 protocolErrors->pushString(String::format("Parameter '%s' has wrong type. It must be '%s'.", name.utf8().data(), typeName));
214 return value;
215 }
216
217 if (valueFound)
218 *valueFound = true;
219
220 return value;
221}
222
223struct AsMethodBridges {
224 static bool asInt(InspectorValue* value, int* output) { return value->asNumber(output); }
225 static bool asDouble(InspectorValue* value, double* output) { return value->asNumber(output); }
226 static bool asString(InspectorValue* value, String* output) { return value->asString(output); }
227 static bool asBoolean(InspectorValue* value, bool* output) { return value->asBoolean(output); }
228 static bool asObject(InspectorValue* value, RefPtr<InspectorObject>* output) { return value->asObject(output); }
229 static bool asArray(InspectorValue* value, RefPtr<InspectorArray>* output) { return value->asArray(output); }
230};
231
232int InspectorBackendDispatcher::getInt(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
233{
234 return getPropertyValue<int, int, int>(object, name, valueFound, protocolErrors, 0, AsMethodBridges::asInt, "Number");
235}
236
237double InspectorBackendDispatcher::getDouble(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
238{
239 return getPropertyValue<double, double, double>(object, name, valueFound, protocolErrors, 0, AsMethodBridges::asDouble, "Number");
240}
241
242String InspectorBackendDispatcher::getString(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
243{
244 return getPropertyValue<String, String, String>(object, name, valueFound, protocolErrors, "", AsMethodBridges::asString, "String");
245}
246
247bool InspectorBackendDispatcher::getBoolean(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
248{
249 return getPropertyValue<bool, bool, bool>(object, name, valueFound, protocolErrors, false, AsMethodBridges::asBoolean, "Boolean");
250}
251
252PassRefPtr<InspectorObject> InspectorBackendDispatcher::getObject(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
253{
254 return getPropertyValue<PassRefPtr<InspectorObject>, RefPtr<InspectorObject>, InspectorObject*>(object, name, valueFound, protocolErrors, nullptr, AsMethodBridges::asObject, "Object");
255}
256
257PassRefPtr<InspectorArray> InspectorBackendDispatcher::getArray(InspectorObject* object, const String& name, bool* valueFound, InspectorArray* protocolErrors)
258{
259 return getPropertyValue<PassRefPtr<InspectorArray>, RefPtr<InspectorArray>, InspectorArray*>(object, name, valueFound, protocolErrors, nullptr, AsMethodBridges::asArray, "Array");
260}
261
262} // namespace Inspector
263
264#endif // ENABLE(INSPECTOR)