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) 265