1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "dispatcher.h"
17
18 #include "agent/debugger_impl.h"
19 #include "agent/runtime_impl.h"
20 #ifdef ECMASCRIPT_SUPPORT_HEAPPROFILER
21 #include "agent/heapprofiler_impl.h"
22 #endif
23 #ifdef ECMASCRIPT_SUPPORT_CPUPROFILER
24 #include "agent/profiler_impl.h"
25 #endif
26 #include "agent/tracing_impl.h"
27 #include "agent/css_impl.h"
28 #include "agent/dom_impl.h"
29 #include "agent/overlay_impl.h"
30 #include "agent/page_impl.h"
31 #include "agent/target_impl.h"
32 #include "protocol_channel.h"
33
34 namespace panda::ecmascript::tooling {
DispatchRequest(const std::string & message)35 DispatchRequest::DispatchRequest(const std::string &message)
36 {
37 std::unique_ptr<PtJson> json = PtJson::Parse(message);
38 if (json == nullptr) {
39 code_ = RequestCode::JSON_PARSE_ERROR;
40 LOG_DEBUGGER(ERROR) << "json parse error";
41 return;
42 }
43 if (!json->IsObject()) {
44 code_ = RequestCode::PARAMS_FORMAT_ERROR;
45 LOG_DEBUGGER(ERROR) << "json parse format error";
46 json->ReleaseRoot();
47 return;
48 }
49
50 Result ret;
51 int32_t callId;
52 ret = json->GetInt("id", &callId);
53 if (ret != Result::SUCCESS) {
54 code_ = RequestCode::PARSE_ID_ERROR;
55 LOG_DEBUGGER(ERROR) << "parse id error";
56 return;
57 }
58 callId_ = callId;
59
60 std::string wholeMethod;
61 ret = json->GetString("method", &wholeMethod);
62 if (ret != Result::SUCCESS) {
63 code_ = RequestCode::PARSE_METHOD_ERROR;
64 LOG_DEBUGGER(ERROR) << "parse method error";
65 return;
66 }
67 std::string::size_type length = wholeMethod.length();
68 std::string::size_type indexPoint;
69 indexPoint = wholeMethod.find_first_of('.', 0);
70 if (indexPoint == std::string::npos || indexPoint == 0 || indexPoint == length - 1) {
71 code_ = RequestCode::METHOD_FORMAT_ERROR;
72 LOG_DEBUGGER(ERROR) << "method format error: " << wholeMethod;
73 return;
74 }
75 domain_ = wholeMethod.substr(0, indexPoint);
76 method_ = wholeMethod.substr(indexPoint + 1, length);
77
78 LOG_DEBUGGER(DEBUG) << "id: " << callId_ << ", domain: " << domain_ << ", method: " << method_;
79
80 std::unique_ptr<PtJson> params;
81 ret = json->GetObject("params", ¶ms);
82 if (ret == Result::NOT_EXIST) {
83 return;
84 }
85 if (ret == Result::TYPE_ERROR) {
86 code_ = RequestCode::PARAMS_FORMAT_ERROR;
87 LOG_DEBUGGER(ERROR) << "params format error";
88 return;
89 }
90 params_ = std::move(params);
91 }
92
~DispatchRequest()93 DispatchRequest::~DispatchRequest()
94 {
95 params_->ReleaseRoot();
96 }
97
Create(ResponseCode code,const std::string & msg)98 DispatchResponse DispatchResponse::Create(ResponseCode code, const std::string &msg)
99 {
100 DispatchResponse response;
101 response.code_ = code;
102 response.errorMsg_ = msg;
103 return response;
104 }
105
Create(std::optional<std::string> error)106 DispatchResponse DispatchResponse::Create(std::optional<std::string> error)
107 {
108 DispatchResponse response;
109 if (error.has_value()) {
110 response.code_ = ResponseCode::NOK;
111 response.errorMsg_ = error.value();
112 }
113 return response;
114 }
115
Ok()116 DispatchResponse DispatchResponse::Ok()
117 {
118 return DispatchResponse();
119 }
120
Fail(const std::string & message)121 DispatchResponse DispatchResponse::Fail(const std::string &message)
122 {
123 DispatchResponse response;
124 response.code_ = ResponseCode::NOK;
125 response.errorMsg_ = message;
126 return response;
127 }
128
SendResponse(const DispatchRequest & request,const DispatchResponse & response,const PtBaseReturns & result)129 void DispatcherBase::SendResponse(const DispatchRequest &request, const DispatchResponse &response,
130 const PtBaseReturns &result)
131 {
132 if (channel_ != nullptr) {
133 channel_->SendResponse(request, response, result);
134 }
135 }
136
Dispatcher(const EcmaVM * vm,ProtocolChannel * channel)137 Dispatcher::Dispatcher(const EcmaVM *vm, ProtocolChannel *channel)
138 {
139 // profiler
140 #ifdef ECMASCRIPT_SUPPORT_CPUPROFILER
141 auto profiler = std::make_unique<ProfilerImpl>(vm, channel);
142 dispatchers_["Profiler"] =
143 std::make_unique<ProfilerImpl::DispatcherImpl>(channel, std::move(profiler));
144 #endif
145 #ifdef ECMASCRIPT_SUPPORT_HEAPPROFILER
146 auto heapProfiler = std::make_unique<HeapProfilerImpl>(vm, channel);
147 dispatchers_["HeapProfiler"] =
148 std::make_unique<HeapProfilerImpl::DispatcherImpl>(channel, std::move(heapProfiler));
149 #endif
150 #ifdef ECMASCRIPT_SUPPORT_TRACING
151 auto tracing = std::make_unique<TracingImpl>(vm, channel);
152 dispatchers_["Tracing"] =
153 std::make_unique<TracingImpl::DispatcherImpl>(channel, std::move(tracing));
154 #endif
155
156 // debugger
157 auto runtime = std::make_unique<RuntimeImpl>(vm, channel);
158 auto debugger = std::make_unique<DebuggerImpl>(vm, channel, runtime.get());
159 dispatchers_["Runtime"] =
160 std::make_unique<RuntimeImpl::DispatcherImpl>(channel, std::move(runtime));
161 dispatchers_["Debugger"] =
162 std::make_unique<DebuggerImpl::DispatcherImpl>(channel, std::move(debugger));
163
164 auto dom = std::make_unique<DomImpl>();
165 dispatchers_["DOM"] =
166 std::make_unique<DomImpl::DispatcherImpl>(channel, std::move(dom));
167
168 auto css = std::make_unique<CssImpl>();
169 dispatchers_["CSS"] =
170 std::make_unique<CssImpl::DispatcherImpl>(channel, std::move(css));
171
172 auto overlay = std::make_unique<OverlayImpl>();
173 dispatchers_["Overlay"] =
174 std::make_unique<OverlayImpl::DispatcherImpl>(channel, std::move(overlay));
175
176 auto target = std::make_unique<TargetImpl>();
177 dispatchers_["Target"] =
178 std::make_unique<TargetImpl::DispatcherImpl>(channel, std::move(target));
179
180 auto page = std::make_unique<PageImpl>();
181 dispatchers_["Page"] =
182 std::make_unique<PageImpl::DispatcherImpl>(channel, std::move(page));
183 }
184
Dispatch(const DispatchRequest & request)185 void Dispatcher::Dispatch(const DispatchRequest &request)
186 {
187 if (!request.IsValid()) {
188 LOG_DEBUGGER(ERROR) << "Unknown request";
189 return;
190 }
191 const std::string &domain = request.GetDomain();
192 auto dispatcher = dispatchers_.find(domain);
193 if (dispatcher != dispatchers_.end()) {
194 dispatcher->second->Dispatch(request);
195 } else {
196 if (domain == "Test") {
197 if (request.GetMethod() == "fail") {
198 LOG_DEBUGGER(FATAL) << "Test fail";
199 UNREACHABLE();
200 }
201 LOG_DEBUGGER(INFO) << "Test success";
202 } else {
203 LOG_DEBUGGER(ERROR) << "unknown domain: " << domain;
204 }
205 }
206 }
207 } // namespace panda::ecmascript::tooling
208