]>
Commit | Line | Data |
---|---|---|
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 | ||
37 | namespace Inspector { | |
38 | ||
39 | InspectorBackendDispatcher::CallbackBase::CallbackBase(PassRefPtr<InspectorBackendDispatcher> backendDispatcher, int id) | |
40 | : m_backendDispatcher(backendDispatcher) | |
41 | , m_id(id) | |
42 | , m_alreadySent(false) | |
43 | { | |
44 | } | |
45 | ||
46 | bool InspectorBackendDispatcher::CallbackBase::isActive() const | |
47 | { | |
48 | return !m_alreadySent && m_backendDispatcher->isActive(); | |
49 | } | |
50 | ||
51 | void InspectorBackendDispatcher::CallbackBase::sendFailure(const ErrorString& error) | |
52 | { | |
53 | ASSERT(error.length()); | |
54 | sendIfActive(nullptr, error); | |
55 | } | |
56 | ||
57 | void 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 | ||
66 | PassRefPtr<InspectorBackendDispatcher> InspectorBackendDispatcher::create(InspectorFrontendChannel* inspectorFrontendChannel) | |
67 | { | |
68 | return adoptRef(new InspectorBackendDispatcher(inspectorFrontendChannel)); | |
69 | } | |
70 | ||
71 | void InspectorBackendDispatcher::registerDispatcherForDomain(const String& domain, InspectorSupplementalBackendDispatcher* dispatcher) | |
72 | { | |
73 | auto result = m_dispatchers.add(domain, dispatcher); | |
74 | ASSERT_UNUSED(result, result.isNewEntry); | |
75 | } | |
76 | ||
77 | void 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 | ||
134 | void 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 | ||
150 | void InspectorBackendDispatcher::reportProtocolError(const long* const callId, CommonErrorCode errorCode, const String& errorMessage) const | |
151 | { | |
152 | reportProtocolError(callId, errorCode, errorMessage, nullptr); | |
153 | } | |
154 | ||
155 | void 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 | ||
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) | |
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 | ||
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); } | |
230 | }; | |
231 | ||
232 | int 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 | ||
237 | double 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 | ||
242 | String 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 | ||
247 | bool 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 | ||
252 | PassRefPtr<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 | ||
257 | PassRefPtr<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) |