2 * Copyright (C) 2013 Apple Inc. All Rights Reserved.
3 * Copyright (C) 2011 The Chromium Authors. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
28 #include "InspectorBackendDispatcher.h"
32 #include "InspectorFrontendChannel.h"
33 #include "InspectorValues.h"
34 #include <wtf/text/CString.h>
35 #include <wtf/text/WTFString.h>
39 InspectorBackendDispatcher::CallbackBase::CallbackBase(PassRefPtr
<InspectorBackendDispatcher
> backendDispatcher
, int id
)
40 : m_backendDispatcher(backendDispatcher
)
42 , m_alreadySent(false)
46 bool InspectorBackendDispatcher::CallbackBase::isActive() const
48 return !m_alreadySent
&& m_backendDispatcher
->isActive();
51 void InspectorBackendDispatcher::CallbackBase::sendFailure(const ErrorString
& error
)
53 ASSERT(error
.length());
54 sendIfActive(nullptr, error
);
57 void InspectorBackendDispatcher::CallbackBase::sendIfActive(PassRefPtr
<InspectorObject
> partialMessage
, const ErrorString
& invocationError
)
62 m_backendDispatcher
->sendResponse(m_id
, partialMessage
, invocationError
);
66 PassRefPtr
<InspectorBackendDispatcher
> InspectorBackendDispatcher::create(InspectorFrontendChannel
* inspectorFrontendChannel
)
68 return adoptRef(new InspectorBackendDispatcher(inspectorFrontendChannel
));
71 void InspectorBackendDispatcher::registerDispatcherForDomain(const String
& domain
, InspectorSupplementalBackendDispatcher
* dispatcher
)
73 auto result
= m_dispatchers
.add(domain
, dispatcher
);
74 ASSERT_UNUSED(result
, result
.isNewEntry
);
77 void InspectorBackendDispatcher::dispatch(const String
& message
)
79 Ref
<InspectorBackendDispatcher
> protect(*this);
81 RefPtr
<InspectorValue
> parsedMessage
= InspectorValue::parseJSON(message
);
83 reportProtocolError(nullptr, ParseError
, ASCIILiteral("Message must be in JSON format"));
87 RefPtr
<InspectorObject
> messageObject
= parsedMessage
->asObject();
89 reportProtocolError(nullptr, InvalidRequest
, ASCIILiteral("Message must be a JSONified object"));
93 RefPtr
<InspectorValue
> callIdValue
= messageObject
->get("id");
95 reportProtocolError(nullptr, InvalidRequest
, ASCIILiteral("'id' property was not found"));
100 if (!callIdValue
->asNumber(&callId
)) {
101 reportProtocolError(nullptr, InvalidRequest
, ASCIILiteral("The type of 'id' property must be number"));
105 RefPtr
<InspectorValue
> methodValue
= messageObject
->get("method");
107 reportProtocolError(&callId
, InvalidRequest
, ASCIILiteral("'method' property wasn't found"));
112 if (!methodValue
->asString(&method
)) {
113 reportProtocolError(&callId
, InvalidRequest
, ASCIILiteral("The type of 'method' property must be string"));
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'"));
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");
130 String domainMethod
= method
.substring(position
+ 1);
131 domainDispatcher
->dispatch(callId
, domainMethod
, messageObject
.release());
134 void InspectorBackendDispatcher::sendResponse(long callId
, PassRefPtr
<InspectorObject
> result
, const ErrorString
& invocationError
)
136 if (!m_inspectorFrontendChannel
)
139 if (invocationError
.length()) {
140 reportProtocolError(&callId
, ServerError
, invocationError
);
144 RefPtr
<InspectorObject
> responseMessage
= InspectorObject::create();
145 responseMessage
->setObject(ASCIILiteral("result"), result
);
146 responseMessage
->setNumber(ASCIILiteral("id"), callId
);
147 m_inspectorFrontendChannel
->sendMessageToFrontend(responseMessage
->toJSONString());
150 void InspectorBackendDispatcher::reportProtocolError(const long* const callId
, CommonErrorCode errorCode
, const String
& errorMessage
) const
152 reportProtocolError(callId
, errorCode
, errorMessage
, nullptr);
155 void InspectorBackendDispatcher::reportProtocolError(const long* const callId
, CommonErrorCode errorCode
, const String
& errorMessage
, PassRefPtr
<InspectorArray
> data
) const
157 static const int errorCodes
[] = {
158 -32700, // ParseError
159 -32600, // InvalidRequest
160 -32601, // MethodNotFound
161 -32602, // InvalidParams
162 -32603, // InternalError
163 -32000, // ServerError
166 ASSERT(errorCode
>= 0);
167 ASSERT((unsigned)errorCode
< WTF_ARRAY_LENGTH(errorCodes
));
168 ASSERT(errorCodes
[errorCode
]);
170 if (!m_inspectorFrontendChannel
)
173 RefPtr
<InspectorObject
> error
= InspectorObject::create();
174 error
->setNumber(ASCIILiteral("code"), errorCodes
[errorCode
]);
175 error
->setString(ASCIILiteral("message"), errorMessage
);
177 error
->setArray(ASCIILiteral("data"), data
);
179 RefPtr
<InspectorObject
> message
= InspectorObject::create();
180 message
->setObject(ASCIILiteral("error"), error
.release());
182 message
->setNumber(ASCIILiteral("id"), *callId
);
184 message
->setValue(ASCIILiteral("id"), InspectorValue::null());
186 m_inspectorFrontendChannel
->sendMessageToFrontend(message
->toJSONString());
189 template<typename ReturnValueType
, typename ValueType
, typename DefaultValueType
>
190 static ReturnValueType
getPropertyValue(InspectorObject
* object
, const String
& name
, bool* valueFound
, InspectorArray
* protocolErrors
, DefaultValueType defaultValue
, bool (*asMethod
)(InspectorValue
*, ValueType
*), const char* typeName
)
192 ASSERT(protocolErrors
);
194 ValueType value
= defaultValue
;
200 protocolErrors
->pushString(String::format("'params' object must contain required parameter '%s' with type '%s'.", name
.utf8().data(), typeName
));
204 InspectorObject::const_iterator end
= object
->end();
205 InspectorObject::const_iterator valueIterator
= object
->find(name
);
206 if (valueIterator
== end
) {
208 protocolErrors
->pushString(String::format("Parameter '%s' with type '%s' was not found.", name
.utf8().data(), typeName
));
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
));
223 struct 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
); }
232 int InspectorBackendDispatcher::getInt(InspectorObject
* object
, const String
& name
, bool* valueFound
, InspectorArray
* protocolErrors
)
234 return getPropertyValue
<int, int, int>(object
, name
, valueFound
, protocolErrors
, 0, AsMethodBridges::asInt
, "Number");
237 double InspectorBackendDispatcher::getDouble(InspectorObject
* object
, const String
& name
, bool* valueFound
, InspectorArray
* protocolErrors
)
239 return getPropertyValue
<double, double, double>(object
, name
, valueFound
, protocolErrors
, 0, AsMethodBridges::asDouble
, "Number");
242 String
InspectorBackendDispatcher::getString(InspectorObject
* object
, const String
& name
, bool* valueFound
, InspectorArray
* protocolErrors
)
244 return getPropertyValue
<String
, String
, String
>(object
, name
, valueFound
, protocolErrors
, "", AsMethodBridges::asString
, "String");
247 bool InspectorBackendDispatcher::getBoolean(InspectorObject
* object
, const String
& name
, bool* valueFound
, InspectorArray
* protocolErrors
)
249 return getPropertyValue
<bool, bool, bool>(object
, name
, valueFound
, protocolErrors
, false, AsMethodBridges::asBoolean
, "Boolean");
252 PassRefPtr
<InspectorObject
> InspectorBackendDispatcher::getObject(InspectorObject
* object
, const String
& name
, bool* valueFound
, InspectorArray
* protocolErrors
)
254 return getPropertyValue
<PassRefPtr
<InspectorObject
>, RefPtr
<InspectorObject
>, InspectorObject
*>(object
, name
, valueFound
, protocolErrors
, nullptr, AsMethodBridges::asObject
, "Object");
257 PassRefPtr
<InspectorArray
> InspectorBackendDispatcher::getArray(InspectorObject
* object
, const String
& name
, bool* valueFound
, InspectorArray
* protocolErrors
)
259 return getPropertyValue
<PassRefPtr
<InspectorArray
>, RefPtr
<InspectorArray
>, InspectorArray
*>(object
, name
, valueFound
, protocolErrors
, nullptr, AsMethodBridges::asArray
, "Array");
262 } // namespace Inspector
264 #endif // ENABLE(INSPECTOR)