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
Dispatcher(const EcmaVM * vm,ProtocolChannel * channel)133 Dispatcher::Dispatcher(const EcmaVM *vm, ProtocolChannel *channel)
134 {
135 // profiler
136 #ifdef ECMASCRIPT_SUPPORT_CPUPROFILER
137 auto profiler = std::make_unique<ProfilerImpl>(vm, channel);
138 dispatchers_["Profiler"] =
139 std::make_unique<ProfilerImpl::DispatcherImpl>(channel, std::move(profiler));
140 #endif
141 #ifdef ECMASCRIPT_SUPPORT_HEAPPROFILER
142 auto heapProfiler = std::make_unique<HeapProfilerImpl>(vm, channel);
143 dispatchers_["HeapProfiler"] =
144 std::make_unique<HeapProfilerImpl::DispatcherImpl>(channel, std::move(heapProfiler));
145 #endif
146 #ifdef ECMASCRIPT_SUPPORT_TRACING
147 auto tracing = std::make_unique<TracingImpl>(vm, channel);
148 dispatchers_["Tracing"] =
149 std::make_unique<TracingImpl::DispatcherImpl>(channel, std::move(tracing));
150 #endif
151
152 // debugger
153 auto runtime = std::make_unique<RuntimeImpl>(vm, channel);
154 auto debugger = std::make_unique<DebuggerImpl>(vm, channel, runtime.get());
155 dispatchers_["Runtime"] =
156 std::make_unique<RuntimeImpl::DispatcherImpl>(channel, std::move(runtime));
157 dispatchers_["Debugger"] =
158 std::make_unique<DebuggerImpl::DispatcherImpl>(channel, std::move(debugger));
159
160 auto dom = std::make_unique<DomImpl>();
161 dispatchers_["DOM"] =
162 std::make_unique<DomImpl::DispatcherImpl>(channel, std::move(dom));
163
164 auto css = std::make_unique<CssImpl>();
165 dispatchers_["CSS"] =
166 std::make_unique<CssImpl::DispatcherImpl>(channel, std::move(css));
167
168 auto overlay = std::make_unique<OverlayImpl>();
169 dispatchers_["Overlay"] =
170 std::make_unique<OverlayImpl::DispatcherImpl>(channel, std::move(overlay));
171
172 auto target = std::make_unique<TargetImpl>();
173 dispatchers_["Target"] =
174 std::make_unique<TargetImpl::DispatcherImpl>(channel, std::move(target));
175
176 auto page = std::make_unique<PageImpl>();
177 dispatchers_["Page"] =
178 std::make_unique<PageImpl::DispatcherImpl>(channel, std::move(page));
179
180 auto animation = std::make_unique<AnimationImpl>();
181 dispatchers_["Animation"] =
182 std::make_unique<AnimationImpl::DispatcherImpl>(channel, std::move(animation));
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
GetJsFrames() const208 std::string Dispatcher::GetJsFrames() const
209 {
210 auto dispatcher = dispatchers_.find("Debugger");
211 if (dispatcher != dispatchers_.end()) {
212 auto debuggerImpl = reinterpret_cast<DebuggerImpl::DispatcherImpl*>(dispatcher->second.get());
213 return debuggerImpl->GetJsFrames();
214 }
215 return "";
216 }
217 } // namespace panda::ecmascript::tooling
218