1// This file is generated by DispatcherBase_cpp.template.
2
3// Copyright 2016 The Chromium Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6
7//#include "DispatcherBase.h"
8//#include "Parser.h"
9
10{% for namespace in config.protocol.namespace %}
11namespace {{namespace}} {
12{% endfor %}
13
14// static
15DispatchResponse DispatchResponse::OK()
16{
17    DispatchResponse result;
18    result.m_status = kSuccess;
19    result.m_errorCode = kParseError;
20    return result;
21}
22
23// static
24DispatchResponse DispatchResponse::Error(const String& error)
25{
26    DispatchResponse result;
27    result.m_status = kError;
28    result.m_errorCode = kServerError;
29    result.m_errorMessage = error;
30    return result;
31}
32
33// static
34DispatchResponse DispatchResponse::InternalError()
35{
36    DispatchResponse result;
37    result.m_status = kError;
38    result.m_errorCode = kInternalError;
39    result.m_errorMessage = "Internal error";
40    return result;
41}
42
43// static
44DispatchResponse DispatchResponse::InvalidParams(const String& error)
45{
46    DispatchResponse result;
47    result.m_status = kError;
48    result.m_errorCode = kInvalidParams;
49    result.m_errorMessage = error;
50    return result;
51}
52
53// static
54DispatchResponse DispatchResponse::FallThrough()
55{
56    DispatchResponse result;
57    result.m_status = kFallThrough;
58    result.m_errorCode = kParseError;
59    return result;
60}
61
62// static
63const char DispatcherBase::kInvalidParamsString[] = "Invalid parameters";
64
65DispatcherBase::WeakPtr::WeakPtr(DispatcherBase* dispatcher) : m_dispatcher(dispatcher) { }
66
67DispatcherBase::WeakPtr::~WeakPtr()
68{
69    if (m_dispatcher)
70        m_dispatcher->m_weakPtrs.erase(this);
71}
72
73DispatcherBase::Callback::Callback(std::unique_ptr<DispatcherBase::WeakPtr> backendImpl, int callId, const String& method, const ProtocolMessage& message)
74    : m_backendImpl(std::move(backendImpl))
75    , m_callId(callId)
76    , m_method(method)
77    , m_message(message) { }
78
79DispatcherBase::Callback::~Callback() = default;
80
81void DispatcherBase::Callback::dispose()
82{
83    m_backendImpl = nullptr;
84}
85
86void DispatcherBase::Callback::sendIfActive(std::unique_ptr<protocol::DictionaryValue> partialMessage, const DispatchResponse& response)
87{
88    if (!m_backendImpl || !m_backendImpl->get())
89        return;
90    m_backendImpl->get()->sendResponse(m_callId, response, std::move(partialMessage));
91    m_backendImpl = nullptr;
92}
93
94void DispatcherBase::Callback::fallThroughIfActive()
95{
96    if (!m_backendImpl || !m_backendImpl->get())
97        return;
98    m_backendImpl->get()->channel()->fallThrough(m_callId, m_method, m_message);
99    m_backendImpl = nullptr;
100}
101
102DispatcherBase::DispatcherBase(FrontendChannel* frontendChannel)
103    : m_frontendChannel(frontendChannel) { }
104
105DispatcherBase::~DispatcherBase()
106{
107    clearFrontend();
108}
109
110void DispatcherBase::sendResponse(int callId, const DispatchResponse& response, std::unique_ptr<protocol::DictionaryValue> result)
111{
112    if (!m_frontendChannel)
113        return;
114    if (response.status() == DispatchResponse::kError) {
115        reportProtocolError(callId, response.errorCode(), response.errorMessage(), nullptr);
116        return;
117    }
118    m_frontendChannel->sendProtocolResponse(callId, InternalResponse::createResponse(callId, std::move(result)));
119}
120
121void DispatcherBase::sendResponse(int callId, const DispatchResponse& response)
122{
123    sendResponse(callId, response, DictionaryValue::create());
124}
125
126namespace {
127
128class ProtocolError : public Serializable {
129public:
130    static std::unique_ptr<ProtocolError> createErrorResponse(int callId, DispatchResponse::ErrorCode code, const String& errorMessage, ErrorSupport* errors)
131    {
132        std::unique_ptr<ProtocolError> protocolError(new ProtocolError(code, errorMessage));
133        protocolError->m_callId = callId;
134        protocolError->m_hasCallId = true;
135        if (errors && errors->hasErrors())
136            protocolError->m_data = errors->errors();
137        return protocolError;
138    }
139
140    static std::unique_ptr<ProtocolError> createErrorNotification(DispatchResponse::ErrorCode code, const String& errorMessage)
141    {
142        return std::unique_ptr<ProtocolError>(new ProtocolError(code, errorMessage));
143    }
144
145    String serializeToJSON() override
146    {
147        return serialize()->serializeToJSON();
148    }
149
150    std::vector<uint8_t> serializeToBinary() override
151    {
152        return serialize()->serializeToBinary();
153    }
154
155    ~ProtocolError() override {}
156
157private:
158    ProtocolError(DispatchResponse::ErrorCode code, const String& errorMessage)
159        : m_code(code)
160        , m_errorMessage(errorMessage)
161    {
162    }
163
164    std::unique_ptr<DictionaryValue> serialize() {
165        std::unique_ptr<protocol::DictionaryValue> error = DictionaryValue::create();
166        error->setInteger("code", m_code);
167        error->setString("message", m_errorMessage);
168        if (m_data.length())
169            error->setString("data", m_data);
170        std::unique_ptr<protocol::DictionaryValue> message = DictionaryValue::create();
171        message->setObject("error", std::move(error));
172        if (m_hasCallId)
173            message->setInteger("id", m_callId);
174        return message;
175    }
176
177    DispatchResponse::ErrorCode m_code;
178    String m_errorMessage;
179    String m_data;
180    int m_callId = 0;
181    bool m_hasCallId = false;
182};
183
184} // namespace
185
186static void reportProtocolErrorTo(FrontendChannel* frontendChannel, int callId, DispatchResponse::ErrorCode code, const String& errorMessage, ErrorSupport* errors)
187{
188    if (frontendChannel)
189        frontendChannel->sendProtocolResponse(callId, ProtocolError::createErrorResponse(callId, code, errorMessage, errors));
190}
191
192static void reportProtocolErrorTo(FrontendChannel* frontendChannel, DispatchResponse::ErrorCode code, const String& errorMessage)
193{
194    if (frontendChannel)
195        frontendChannel->sendProtocolNotification(ProtocolError::createErrorNotification(code, errorMessage));
196}
197
198void DispatcherBase::reportProtocolError(int callId, DispatchResponse::ErrorCode code, const String& errorMessage, ErrorSupport* errors)
199{
200    reportProtocolErrorTo(m_frontendChannel, callId, code, errorMessage, errors);
201}
202
203void DispatcherBase::clearFrontend()
204{
205    m_frontendChannel = nullptr;
206    for (auto& weak : m_weakPtrs)
207        weak->dispose();
208    m_weakPtrs.clear();
209}
210
211std::unique_ptr<DispatcherBase::WeakPtr> DispatcherBase::weakPtr()
212{
213    std::unique_ptr<DispatcherBase::WeakPtr> weak(new DispatcherBase::WeakPtr(this));
214    m_weakPtrs.insert(weak.get());
215    return weak;
216}
217
218UberDispatcher::UberDispatcher(FrontendChannel* frontendChannel)
219    : m_frontendChannel(frontendChannel) { }
220
221void UberDispatcher::registerBackend(const String& name, std::unique_ptr<protocol::DispatcherBase> dispatcher)
222{
223    m_dispatchers[name] = std::move(dispatcher);
224}
225
226void UberDispatcher::setupRedirects(const std::unordered_map<String, String>& redirects)
227{
228    for (const auto& pair : redirects)
229        m_redirects[pair.first] = pair.second;
230}
231
232bool UberDispatcher::parseCommand(Value* parsedMessage, int* outCallId, String* outMethod) {
233    if (!parsedMessage) {
234        reportProtocolErrorTo(m_frontendChannel, DispatchResponse::kParseError, "Message must be a valid JSON");
235        return false;
236    }
237    protocol::DictionaryValue* messageObject = DictionaryValue::cast(parsedMessage);
238    if (!messageObject) {
239        reportProtocolErrorTo(m_frontendChannel, DispatchResponse::kInvalidRequest, "Message must be an object");
240        return false;
241    }
242
243    int callId = 0;
244    protocol::Value* callIdValue = messageObject->get("id");
245    bool success = callIdValue && callIdValue->asInteger(&callId);
246    if (!success) {
247        reportProtocolErrorTo(m_frontendChannel, DispatchResponse::kInvalidRequest, "Message must have integer 'id' property");
248        return false;
249    }
250    if (outCallId)
251      *outCallId = callId;
252
253    protocol::Value* methodValue = messageObject->get("method");
254    String method;
255    success = methodValue && methodValue->asString(&method);
256    if (!success) {
257        reportProtocolErrorTo(m_frontendChannel, callId, DispatchResponse::kInvalidRequest, "Message must have string 'method' property", nullptr);
258        return false;
259    }
260    if (outMethod)
261      *outMethod = method;
262    return true;
263}
264
265protocol::DispatcherBase* UberDispatcher::findDispatcher(const String& method) {
266    size_t dotIndex = StringUtil::find(method, ".");
267    if (dotIndex == StringUtil::kNotFound)
268        return nullptr;
269    String domain = StringUtil::substring(method, 0, dotIndex);
270    auto it = m_dispatchers.find(domain);
271    if (it == m_dispatchers.end())
272        return nullptr;
273    if (!it->second->canDispatch(method))
274        return nullptr;
275    return it->second.get();
276}
277
278bool UberDispatcher::canDispatch(const String& in_method)
279{
280    String method = in_method;
281    auto redirectIt = m_redirects.find(method);
282    if (redirectIt != m_redirects.end())
283        method = redirectIt->second;
284    return !!findDispatcher(method);
285}
286
287void UberDispatcher::dispatch(int callId, const String& in_method, std::unique_ptr<Value> parsedMessage, const ProtocolMessage& rawMessage)
288{
289    String method = in_method;
290    auto redirectIt = m_redirects.find(method);
291    if (redirectIt != m_redirects.end())
292        method = redirectIt->second;
293    protocol::DispatcherBase* dispatcher = findDispatcher(method);
294    if (!dispatcher) {
295        reportProtocolErrorTo(m_frontendChannel, callId, DispatchResponse::kMethodNotFound, "'" + method + "' wasn't found", nullptr);
296        return;
297    }
298    std::unique_ptr<protocol::DictionaryValue> messageObject = DictionaryValue::cast(std::move(parsedMessage));
299    dispatcher->dispatch(callId, method, rawMessage, std::move(messageObject));
300}
301
302UberDispatcher::~UberDispatcher() = default;
303
304// static
305std::unique_ptr<InternalResponse> InternalResponse::createResponse(int callId, std::unique_ptr<Serializable> params)
306{
307    return std::unique_ptr<InternalResponse>(new InternalResponse(callId, String(), std::move(params)));
308}
309
310// static
311std::unique_ptr<InternalResponse> InternalResponse::createNotification(const String& notification, std::unique_ptr<Serializable> params)
312{
313    return std::unique_ptr<InternalResponse>(new InternalResponse(0, notification, std::move(params)));
314}
315
316String InternalResponse::serializeToJSON()
317{
318    std::unique_ptr<DictionaryValue> result = DictionaryValue::create();
319    std::unique_ptr<Serializable> params(m_params ? std::move(m_params) : DictionaryValue::create());
320    if (m_notification.length()) {
321        result->setString("method", m_notification);
322        result->setValue("params", SerializedValue::fromJSON(params->serializeToJSON()));
323    } else {
324        result->setInteger("id", m_callId);
325        result->setValue("result", SerializedValue::fromJSON(params->serializeToJSON()));
326    }
327    return result->serializeToJSON();
328}
329
330std::vector<uint8_t> InternalResponse::serializeToBinary()
331{
332    std::unique_ptr<DictionaryValue> result = DictionaryValue::create();
333    std::unique_ptr<Serializable> params(m_params ? std::move(m_params) : DictionaryValue::create());
334    if (m_notification.length()) {
335        result->setString("method", m_notification);
336        result->setValue("params", SerializedValue::fromBinary(params->serializeToBinary()));
337    } else {
338        result->setInteger("id", m_callId);
339        result->setValue("result", SerializedValue::fromBinary(params->serializeToBinary()));
340    }
341    return result->serializeToBinary();
342}
343
344InternalResponse::InternalResponse(int callId, const String& notification, std::unique_ptr<Serializable> params)
345    : m_callId(callId)
346    , m_notification(notification)
347    , m_params(params ? std::move(params) : nullptr)
348{
349}
350
351{% for namespace in config.protocol.namespace %}
352} // namespace {{namespace}}
353{% endfor %}
354