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 #ifdef ECMASCRIPT_SUPPORT_HEAPPROFILER
20 #include "agent/heapprofiler_impl.h"
21 #endif
22 #ifdef ECMASCRIPT_SUPPORT_CPUPROFILER
23 #include "agent/profiler_impl.h"
24 #endif
25 #include "agent/animation_impl.h"
26 #include "agent/css_impl.h"
27 #include "agent/dom_impl.h"
28 #include "agent/overlay_impl.h"
29 #include "agent/page_impl.h"
30 #include "agent/target_impl.h"
31 #include "agent/tracing_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 JsonParseError();
40 return;
41 }
42 if (!json->IsObject()) {
43 JsonFormatError(json);
44 return;
45 }
46
47 Result ret;
48 int32_t callId;
49 ret = json->GetInt("id", &callId);
50 if (ret != Result::SUCCESS) {
51 code_ = RequestCode::PARSE_ID_ERROR;
52 LOG_DEBUGGER(ERROR) << "parse id error";
53 return;
54 }
55 callId_ = callId;
56
57 std::string wholeMethod;
58 ret = json->GetString("method", &wholeMethod);
59 if (ret != Result::SUCCESS || wholeMethod.empty()) {
60 code_ = RequestCode::PARSE_METHOD_ERROR;
61 LOG_DEBUGGER(ERROR) << "parse method error";
62 return;
63 }
64 std::string::size_type length = wholeMethod.length();
65 std::string::size_type indexPoint = wholeMethod.find_first_of('.', 0);
66 if (indexPoint == std::string::npos || indexPoint == 0 || indexPoint == length - 1) {
67 code_ = RequestCode::METHOD_FORMAT_ERROR;
68 LOG_DEBUGGER(ERROR) << "method format error: " << wholeMethod;
69 return;
70 }
71 domain_ = wholeMethod.substr(0, indexPoint);
72 method_ = wholeMethod.substr(indexPoint + 1, length);
73
74 LOG_DEBUGGER(DEBUG) << "id: " << callId_ << ", domain: " << domain_ << ", method: " << method_;
75
76 std::unique_ptr<PtJson> params;
77 ret = json->GetObject("params", ¶ms);
78 if (ret == Result::NOT_EXIST) {
79 return;
80 }
81 if (ret == Result::TYPE_ERROR) {
82 code_ = RequestCode::PARAMS_FORMAT_ERROR;
83 LOG_DEBUGGER(ERROR) << "params format error";
84 return;
85 }
86 params_ = std::move(params);
87 }
88
~DispatchRequest()89 DispatchRequest::~DispatchRequest()
90 {
91 params_->ReleaseRoot();
92 }
93
Create(ResponseCode code,const std::string & msg)94 DispatchResponse DispatchResponse::Create(ResponseCode code, const std::string &msg)
95 {
96 DispatchResponse response;
97 response.code_ = code;
98 response.errorMsg_ = msg;
99 return response;
100 }
101
Create(std::optional<std::string> error)102 DispatchResponse DispatchResponse::Create(std::optional<std::string> error)
103 {
104 DispatchResponse response;
105 if (error.has_value()) {
106 response.code_ = ResponseCode::NOK;
107 response.errorMsg_ = error.value();
108 }
109 return response;
110 }
111
Ok()112 DispatchResponse DispatchResponse::Ok()
113 {
114 return DispatchResponse();
115 }
116
Fail(const std::string & message)117 DispatchResponse DispatchResponse::Fail(const std::string &message)
118 {
119 DispatchResponse response;
120 response.code_ = ResponseCode::NOK;
121 response.errorMsg_ = message;
122 return response;
123 }
124
SendResponse(const DispatchRequest & request,const DispatchResponse & response,const PtBaseReturns & result)125 void DispatcherBase::SendResponse(const DispatchRequest &request, const DispatchResponse &response,
126 const PtBaseReturns &result)
127 {
128 if (channel_ != nullptr) {
129 channel_->SendResponse(request, response, result);
130 }
131 }
132
ReturnsValueToString(const int32_t callId,const std::unique_ptr<PtJson> resultObj)133 std::string DispatcherBase::ReturnsValueToString(const int32_t callId, const std::unique_ptr<PtJson> resultObj)
134 {
135 std::unique_ptr<PtJson> ptJson = PtJson::CreateObject();
136 ptJson->Add("id", callId);
137 ptJson->Add("result", resultObj);
138 std::string str = ptJson->Stringify();
139 if (str.empty()) {
140 LOG_DEBUGGER(ERROR) << "Dispatcher::ReturnsValueToString: json stringify error";
141 return "";
142 }
143 ptJson->ReleaseRoot();
144 return str;
145 }
146
DispatchResponseToJson(const DispatchResponse & response) const147 std::unique_ptr<PtJson> DispatcherBase::DispatchResponseToJson(const DispatchResponse &response) const
148 {
149 std::unique_ptr<PtJson> result = PtJson::CreateObject();
150
151 if (!response.IsOk()) {
152 result->Add("code", static_cast<int32_t>(response.GetError()));
153 result->Add("message", response.GetMessage().c_str());
154 }
155
156 return result;
157 }
158
Dispatcher(const EcmaVM * vm,ProtocolChannel * channel)159 Dispatcher::Dispatcher(const EcmaVM *vm, ProtocolChannel *channel)
160 {
161 // profiler
162 #ifdef ECMASCRIPT_SUPPORT_CPUPROFILER
163 auto profiler = std::make_unique<ProfilerImpl>(vm, channel);
164 dispatchers_["Profiler"] =
165 std::make_unique<ProfilerImpl::DispatcherImpl>(channel, std::move(profiler));
166 #endif
167 #ifdef ECMASCRIPT_SUPPORT_HEAPPROFILER
168 auto heapProfiler = std::make_unique<HeapProfilerImpl>(vm, channel);
169 dispatchers_["HeapProfiler"] =
170 std::make_unique<HeapProfilerImpl::DispatcherImpl>(channel, std::move(heapProfiler));
171 #endif
172 #ifdef ECMASCRIPT_SUPPORT_TRACING
173 auto tracing = std::make_unique<TracingImpl>(vm, channel);
174 dispatchers_["Tracing"] =
175 std::make_unique<TracingImpl::DispatcherImpl>(channel, std::move(tracing));
176 #endif
177
178 // debugger
179 auto runtime = std::make_unique<RuntimeImpl>(vm, channel);
180 auto debugger = std::make_unique<DebuggerImpl>(vm, channel, runtime.get());
181 dispatchers_["Runtime"] =
182 std::make_unique<RuntimeImpl::DispatcherImpl>(channel, std::move(runtime));
183 dispatchers_["Debugger"] =
184 std::make_unique<DebuggerImpl::DispatcherImpl>(channel, std::move(debugger));
185
186 auto dom = std::make_unique<DomImpl>();
187 dispatchers_["DOM"] =
188 std::make_unique<DomImpl::DispatcherImpl>(channel, std::move(dom));
189
190 auto css = std::make_unique<CssImpl>();
191 dispatchers_["CSS"] =
192 std::make_unique<CssImpl::DispatcherImpl>(channel, std::move(css));
193
194 auto overlay = std::make_unique<OverlayImpl>();
195 dispatchers_["Overlay"] =
196 std::make_unique<OverlayImpl::DispatcherImpl>(channel, std::move(overlay));
197
198 auto target = std::make_unique<TargetImpl>();
199 dispatchers_["Target"] =
200 std::make_unique<TargetImpl::DispatcherImpl>(channel, std::move(target));
201
202 auto page = std::make_unique<PageImpl>();
203 dispatchers_["Page"] =
204 std::make_unique<PageImpl::DispatcherImpl>(channel, std::move(page));
205
206 auto animation = std::make_unique<AnimationImpl>();
207 dispatchers_["Animation"] =
208 std::make_unique<AnimationImpl::DispatcherImpl>(channel, std::move(animation));
209 }
210
Dispatch(const DispatchRequest & request)211 void Dispatcher::Dispatch(const DispatchRequest &request)
212 {
213 if (!request.IsValid()) {
214 LOG_DEBUGGER(ERROR) << "Unknown request";
215 return;
216 }
217 const std::string &domain = request.GetDomain();
218 auto dispatcher = dispatchers_.find(domain);
219 if (dispatcher != dispatchers_.end()) {
220 dispatcher->second->Dispatch(request);
221 } else {
222 if (domain == "Test") {
223 if (request.GetMethod() == "fail") {
224 LOG_DEBUGGER(FATAL) << "Test fail";
225 UNREACHABLE();
226 }
227 LOG_DEBUGGER(INFO) << "Test success";
228 } else {
229 LOG_DEBUGGER(ERROR) << "unknown domain: " << domain;
230 }
231 }
232 }
233
OperateDebugMessage(const char * message) const234 std::string Dispatcher::OperateDebugMessage(const char* message) const
235 {
236 DispatchRequest request(message);
237 const std::string &domain = request.GetDomain();
238 auto dispatcher = dispatchers_.find(domain);
239 if (dispatcher == dispatchers_.end()) {
240 LOG_DEBUGGER(ERROR) << "unknown domain: " << domain;
241 return "";
242 }
243 std::string method = request.GetMethod();
244 MethodType methodType = GetMethodType(method);
245 switch (methodType) {
246 case MethodType::SAVE_ALL_POSSIBLE_BREAKPOINTS:
247 return SaveAllBreakpoints(request, dispatcher->second.get());
248 case MethodType::REMOVE_BREAKPOINTS_BY_URL:
249 return RemoveBreakpoint(request, dispatcher->second.get());
250 case MethodType::GET_POSSIBLE_AND_SET_BREAKPOINT_BY_URL:
251 return SetBreakpoint(request, dispatcher->second.get());
252 case MethodType::GET_PROPERTIES:
253 return GetProperties(request, dispatcher->second.get());
254 case MethodType::CALL_FUNCTION_ON:
255 return CallFunctionOn(request, dispatcher->second.get());
256 case MethodType::EVALUATE_ON_CALL_FRAME:
257 return EvaluateOnCallFrame(request, dispatcher->second.get());
258 default:
259 LOG_DEBUGGER(ERROR) << "unknown method: " << method;
260 return "";
261 }
262 return "";
263 }
264
GetMethodType(const std::string & method) const265 Dispatcher::MethodType Dispatcher::GetMethodType(const std::string &method) const
266 {
267 static const std::unordered_map<std::string, MethodType> methodMap = {
268 {"saveAllPossibleBreakpoints", MethodType::SAVE_ALL_POSSIBLE_BREAKPOINTS},
269 {"removeBreakpointsByUrl", MethodType::REMOVE_BREAKPOINTS_BY_URL},
270 {"getPossibleAndSetBreakpointByUrl", MethodType::GET_POSSIBLE_AND_SET_BREAKPOINT_BY_URL},
271 {"getProperties", MethodType::GET_PROPERTIES},
272 {"callFunctionOn", MethodType::CALL_FUNCTION_ON},
273 {"evaluateOnCallFrame", MethodType::EVALUATE_ON_CALL_FRAME}
274 };
275 auto it = methodMap.find(method);
276 if (it == methodMap.end()) {
277 LOG_DEBUGGER(ERROR) << "unknown method: " << method;
278 return MethodType::UNKNOWN;
279 }
280 return it->second;
281 }
282
GetJsFrames() const283 std::string Dispatcher::GetJsFrames() const
284 {
285 auto dispatcher = dispatchers_.find("Debugger");
286 if (dispatcher != dispatchers_.end()) {
287 auto debuggerImpl = reinterpret_cast<DebuggerImpl::DispatcherImpl*>(dispatcher->second.get());
288 return debuggerImpl->GetJsFrames();
289 }
290 return "";
291 }
292
SaveAllBreakpoints(const DispatchRequest & request,DispatcherBase * dispatcher) const293 std::string Dispatcher::SaveAllBreakpoints(const DispatchRequest &request, DispatcherBase *dispatcher) const
294 {
295 auto debuggerImpl = reinterpret_cast<DebuggerImpl::DispatcherImpl*>(dispatcher);
296 std::unique_ptr<SaveAllPossibleBreakpointsParams> params =
297 SaveAllPossibleBreakpointsParams::Create(request.GetParams());
298 return debuggerImpl->SaveAllPossibleBreakpoints(request.GetCallId(), std::move(params));
299 }
300
RemoveBreakpoint(const DispatchRequest & request,DispatcherBase * dispatcher) const301 std::string Dispatcher::RemoveBreakpoint(const DispatchRequest &request, DispatcherBase *dispatcher) const
302 {
303 auto debuggerImpl = reinterpret_cast<DebuggerImpl::DispatcherImpl*>(dispatcher);
304 std::unique_ptr<RemoveBreakpointsByUrlParams> params =
305 RemoveBreakpointsByUrlParams::Create(request.GetParams());
306 return debuggerImpl->RemoveBreakpointsByUrl(request.GetCallId(), std::move(params));
307 }
308
SetBreakpoint(const DispatchRequest & request,DispatcherBase * dispatcher) const309 std::string Dispatcher::SetBreakpoint(const DispatchRequest &request, DispatcherBase *dispatcher) const
310 {
311 auto debuggerImpl = reinterpret_cast<DebuggerImpl::DispatcherImpl*>(dispatcher);
312 std::unique_ptr<GetPossibleAndSetBreakpointParams> params =
313 GetPossibleAndSetBreakpointParams::Create(request.GetParams());
314 return debuggerImpl->GetPossibleAndSetBreakpointByUrl(request.GetCallId(), std::move(params));
315 }
316
GetProperties(const DispatchRequest & request,DispatcherBase * dispatcher) const317 std::string Dispatcher::GetProperties(const DispatchRequest &request, DispatcherBase *dispatcher) const
318 {
319 auto runtimeImpl = reinterpret_cast<RuntimeImpl::DispatcherImpl*>(dispatcher);
320 std::unique_ptr<GetPropertiesParams> params = GetPropertiesParams::Create(request.GetParams());
321 return runtimeImpl->GetProperties(request.GetCallId(), std::move(params));
322 }
323
CallFunctionOn(const DispatchRequest & request,DispatcherBase * dispatcher) const324 std::string Dispatcher::CallFunctionOn(const DispatchRequest &request, DispatcherBase *dispatcher) const
325 {
326 auto debuggerImpl = reinterpret_cast<DebuggerImpl::DispatcherImpl*>(dispatcher);
327 std::unique_ptr<CallFunctionOnParams> params = CallFunctionOnParams::Create(request.GetParams());
328 return debuggerImpl->CallFunctionOn(request.GetCallId(), std::move(params));
329 }
330
EvaluateOnCallFrame(const DispatchRequest & request,DispatcherBase * dispatcher) const331 std::string Dispatcher::EvaluateOnCallFrame(const DispatchRequest &request, DispatcherBase *dispatcher) const
332 {
333 auto debuggerImpl = reinterpret_cast<DebuggerImpl::DispatcherImpl*>(dispatcher);
334 std::unique_ptr<EvaluateOnCallFrameParams> params = EvaluateOnCallFrameParams::Create(request.GetParams());
335 return debuggerImpl->EvaluateOnCallFrame(request.GetCallId(), std::move(params));
336 }
337 } // namespace panda::ecmascript::tooling
338