Skip to content

Commit 84ff73b

Browse files
authored
Added HTTP JSON RPC handler (#586)
* Added HTTP JSON RPC handler Signed-off-by: ortyomka <[email protected]>
1 parent 7c44628 commit 84ff73b

File tree

5 files changed

+134
-68
lines changed

5 files changed

+134
-68
lines changed

core/api/rpc/ws.cpp

Lines changed: 88 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,34 @@ namespace fc::api {
3232

3333
const auto kChanCloseDelay{boost::posix_time::milliseconds(100)};
3434

35+
void handleJSONRpcRequest(const Outcome<Document> &j_req,
36+
const Rpc &rpc,
37+
rpc::MakeChan make_chan,
38+
rpc::Send send,
39+
const Permissions &perms,
40+
std::function<void(const Response &)> cb) {
41+
if (!j_req) {
42+
return cb(Response{{}, Response::Error{kParseError, "Parse error"}});
43+
}
44+
auto maybe_req = decode<Request>(*j_req);
45+
if (!maybe_req) {
46+
return cb(
47+
Response{{}, Response::Error{kInvalidRequest, "Invalid request"}});
48+
}
49+
auto &req = maybe_req.value();
50+
auto respond = [id{req.id}, cb](auto res) {
51+
if (id) {
52+
cb(Response{*id, std::move(res)});
53+
}
54+
};
55+
auto it = rpc.ms.find(req.method);
56+
if (it == rpc.ms.end() || !it->second) {
57+
spdlog::error("rpc method {} not implemented", req.method);
58+
return respond(Response::Error{kMethodNotFound, "Method not found"});
59+
}
60+
it->second(req.params, std::move(respond), make_chan, send, perms);
61+
}
62+
3563
struct SocketSession : std::enable_shared_from_this<SocketSession> {
3664
SocketSession(tcp::socket &&socket, Rpc api_rpc, Permissions &&perms)
3765
: socket{std::move(socket)},
@@ -64,30 +92,10 @@ namespace fc::api {
6492
buffer.cdata().size()};
6593
auto j_req{codec::json::parse(s_req)};
6694
buffer.clear();
67-
if (!j_req) {
68-
return _write(Response{{}, Response::Error{kParseError, "Parse error"}},
69-
{});
70-
}
71-
auto maybe_req = decode<Request>(*j_req);
72-
if (!maybe_req) {
73-
return _write(
74-
Response{{}, Response::Error{kInvalidRequest, "Invalid request"}},
75-
{});
76-
}
77-
auto &req = maybe_req.value();
78-
auto respond = [id{req.id}, self{shared_from_this()}](auto res) {
79-
if (id) {
80-
self->_write(Response{*id, std::move(res)}, {});
81-
}
82-
};
83-
auto it = rpc.ms.find(req.method);
84-
if (it == rpc.ms.end() || !it->second) {
85-
spdlog::error("rpc method {} not implemented", req.method);
86-
return respond(Response::Error{kMethodNotFound, "Method not found"});
87-
}
88-
it->second(
89-
req.params,
90-
std::move(respond),
95+
96+
handleJSONRpcRequest(
97+
j_req,
98+
rpc,
9199
[&]() { return next_channel++; },
92100
[self{shared_from_this()}](auto method, auto params, auto cb) {
93101
Request req{self->next_request++, method, std::move(params)};
@@ -101,7 +109,10 @@ namespace fc::api {
101109
}
102110
self->_write(req, std::move(cb));
103111
},
104-
perms);
112+
perms,
113+
[self{shared_from_this()}](const Response &resp) {
114+
self->_write(resp, {});
115+
});
105116
}
106117

107118
template <typename T>
@@ -149,7 +160,7 @@ namespace fc::api {
149160
};
150161

151162
std::optional<std::string> getToken(
152-
const http::request<http::dynamic_body> &request) {
163+
const http::request<http::string_body> &request) {
153164
auto it = request.find(http::field::authorization);
154165
if (it != request.cend()) {
155166
auto auth_token = (it->value());
@@ -176,7 +187,7 @@ namespace fc::api {
176187
}
177188

178189
WrapperResponse makeErrorResponse(
179-
const http::request<http::dynamic_body> &request, http::status status) {
190+
const http::request<http::string_body> &request, http::status status) {
180191
http::response<http::empty_body> response;
181192
response.version(request.version());
182193
response.keep_alive(false);
@@ -257,8 +268,11 @@ namespace fc::api {
257268
if (request.target().starts_with(route.first)) {
258269
boost::asio::post(stream.get_executor(),
259270
[self{shared_from_this()}, fn{route.second}]() {
260-
self->w_response = fn(self->request);
261-
self->doWrite();
271+
fn(self->request,
272+
[self](WrapperResponse response) {
273+
self->w_response = std::move(response);
274+
self->doWrite();
275+
});
262276
});
263277
is_handled = true;
264278
break;
@@ -318,7 +332,7 @@ namespace fc::api {
318332

319333
beast::tcp_stream stream;
320334
beast::flat_buffer buffer;
321-
http::request<http::dynamic_body> request;
335+
http::request<http::string_body> request;
322336
WrapperResponse w_response;
323337
std::shared_ptr<Routes> routes;
324338
std::map<std::string, std::shared_ptr<Rpc>> rpc;
@@ -370,26 +384,65 @@ namespace fc::api {
370384
RouteHandler makeAuthRoute(AuthRouteHandler &&handler,
371385
rpc::AuthFunction &&auth) {
372386
return [handler{std::move(handler)}, auth{std::move(auth)}](
373-
const http::request<http::dynamic_body> &request)
374-
-> WrapperResponse {
387+
const http::request<http::string_body> &request,
388+
const RouteCB &cb) {
375389
Permissions perms = kDefaultPermission;
376390
if (auth) {
377391
const auto maybe_token = getToken(request);
378392
if (not maybe_token.has_value()) {
379-
return makeErrorResponse(request, http::status::unauthorized);
393+
return cb(makeErrorResponse(request, http::status::unauthorized));
380394
}
381395

382396
if (not maybe_token.value().empty()) {
383397
auto maybe_perms =
384398
auth(static_cast<std::string>(maybe_token.value()));
385399
if (maybe_perms.has_error()) {
386-
return makeErrorResponse(request, http::status::unauthorized);
400+
return cb(makeErrorResponse(request, http::status::unauthorized));
387401
}
388402
perms = std::move(maybe_perms.value());
389403
}
390404
}
391405

392-
return handler(request, perms);
406+
handler(request, perms, cb);
407+
};
408+
}
409+
410+
AuthRouteHandler makeHttpRpc(std::shared_ptr<Rpc> rpc) {
411+
return [rpc](const http::request<http::string_body> &request,
412+
const api::Permissions &perms,
413+
const RouteCB &cb) {
414+
std::string_view s_req(request.body().data(), request.body().size());
415+
auto j_req{codec::json::parse(s_req)};
416+
417+
// TODO(ortyomka): Make error if channel requested
418+
handleJSONRpcRequest(
419+
j_req, *rpc, {}, {}, perms, [cb, request](const Response &resp) {
420+
auto data = *codec::json::format(encode(resp));
421+
http::response<http::string_body> response;
422+
response.version(request.version());
423+
response.keep_alive(false);
424+
response.set(http::field::content_type, "application/json");
425+
response.body() = common::span::bytestr(data);
426+
427+
if (auto *error = boost::get<Response::Error>(&(resp.result));
428+
error) {
429+
switch (error->code) {
430+
case kInvalidRequest:
431+
response.result(http::status::bad_request);
432+
break;
433+
case kMethodNotFound:
434+
response.result(http::status::not_found);
435+
break;
436+
case kParseError:
437+
case kInvalidParams:
438+
case kInternalError:
439+
default:
440+
response.result(http::status::internal_server_error);
441+
}
442+
}
443+
444+
cb(api::WrapperResponse(std::move(response)));
445+
});
393446
};
394447
}
395448

core/api/rpc/ws.hpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,17 @@ namespace fc::api {
5353
};
5454

5555
api::WrapperResponse makeErrorResponse(
56-
const http::request<http::dynamic_body> &request, http::status status);
57-
58-
// RouteHandler should write response
59-
using RouteHandler = std::function<WrapperResponse(
60-
const http::request<http::dynamic_body> &request)>;
61-
// AuthRouteHandler should write response
62-
using AuthRouteHandler = std::function<WrapperResponse(
63-
const http::request<http::dynamic_body> &request, const Permissions &perms)>;
56+
const http::request<http::string_body> &request, http::status status);
57+
58+
using RouteCB = std::function<void(WrapperResponse &&)>;
59+
using RouteHandler = std::function<void(
60+
const http::request<http::string_body> &request, const RouteCB &)>;
61+
using AuthRouteHandler =
62+
std::function<void(const http::request<http::string_body> &request,
63+
const Permissions &perms,
64+
const RouteCB &)>;
6465
RouteHandler makeAuthRoute(AuthRouteHandler &&handler, AuthFunction &&auth);
66+
AuthRouteHandler makeHttpRpc(std::shared_ptr<Rpc> rpc);
6567

6668
using Routes = std::map<std::string, RouteHandler, std::greater<>>;
6769

core/miner/main/main.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ namespace fc {
100100
boost::optional<boost::filesystem::path> preseal_path;
101101
boost::optional<boost::filesystem::path> preseal_meta_path;
102102

103+
bool disable_http_rpc{};
104+
103105
auto join(const std::string &path) const {
104106
return (repo_path / path).string();
105107
}
@@ -160,6 +162,8 @@ namespace fc {
160162
option("pre-sealed-metadata",
161163
po::value(&config.preseal_meta_path),
162164
"Path to presealed metadata");
165+
option("disable-http-rpc",
166+
po::bool_switch(&config.disable_http_rpc)->default_value(false));
163167
desc.add(configProfile());
164168
primitives::address::configCurrentNetwork(option);
165169

@@ -542,17 +546,23 @@ namespace fc {
542546
api::fillNetApi(mapi, api_peer_info, host, api::kStorageApiLogger);
543547

544548
std::map<std::string, std::shared_ptr<api::Rpc>> mrpc;
545-
mrpc.emplace(
546-
"/rpc/v0",
547-
api::makeRpc(*mapi,
548-
std::bind(mapi->AuthVerify, std::placeholders::_1)));
549+
auto rpc_handler =
550+
api::makeRpc(*mapi, std::bind(mapi->AuthVerify, std::placeholders::_1));
551+
mrpc.emplace("/rpc/v0", rpc_handler);
549552
auto mroutes{std::make_shared<api::Routes>()};
550-
mroutes->emplace("/health", [](auto &) {
553+
mroutes->emplace("/health", [](auto &, auto &cb) {
551554
api::http::response<api::http::string_body> res;
552555
res.body() = "{\"status\":\"UP\"}";
553-
return api::WrapperResponse{std::move(res)};
556+
cb(api::WrapperResponse{std::move(res)});
554557
});
555558

559+
if (not config.disable_http_rpc) {
560+
mroutes->emplace("/rpc/v0",
561+
api::makeAuthRoute(
562+
api::makeHttpRpc(rpc_handler),
563+
std::bind(mapi->AuthVerify, std::placeholders::_1)));
564+
}
565+
556566
mroutes->insert({"/remote",
557567
api::makeAuthRoute(
558568
sector_storage::serveHttp(local_store),

core/node/main/main.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,10 +222,10 @@ namespace fc {
222222
auto routes{std::make_shared<api::Routes>()};
223223

224224
auto text_route{[](auto f) -> api::RouteHandler {
225-
return [f{std::move(f)}](auto &) {
225+
return [f{std::move(f)}](auto &, auto &cb) {
226226
api::http::response<api::http::string_body> res;
227227
res.body() = f();
228-
return api::WrapperResponse{std::move(res)};
228+
cb(api::WrapperResponse{std::move(res)});
229229
};
230230
}};
231231
routes->emplace("/health",

core/sector_storage/impl/fetch_handler.cpp

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace fc::sector_storage {
2222
common::Logger server_logger = common::createLogger("remote server");
2323

2424
api::WrapperResponse remoteStatFs(
25-
const http::request<http::dynamic_body> &request,
25+
const http::request<http::string_body> &request,
2626
const std::shared_ptr<stores::LocalStore> &local_store,
2727
const common::Logger &logger,
2828
const fc::primitives::StorageID &storage_id) {
@@ -58,7 +58,7 @@ namespace fc::sector_storage {
5858
}
5959

6060
api::WrapperResponse remoteGetSector(
61-
const http::request<http::dynamic_body> &request,
61+
const http::request<http::string_body> &request,
6262
const std::shared_ptr<stores::LocalStore> &local_store,
6363
const common::Logger &logger,
6464
const std::string &type,
@@ -152,7 +152,7 @@ namespace fc::sector_storage {
152152
}
153153

154154
api::WrapperResponse remoteRemoveSector(
155-
const http::request<http::dynamic_body> &request,
155+
const http::request<http::string_body> &request,
156156
const std::shared_ptr<stores::LocalStore> &local_store,
157157
const common::Logger &logger,
158158
const std::string &type,
@@ -193,11 +193,12 @@ namespace fc::sector_storage {
193193
api::AuthRouteHandler serveHttp(
194194
const std::shared_ptr<stores::LocalStore> &local_store) {
195195
return [local = local_store, logger = server_logger](
196-
const http::request<http::dynamic_body> &request,
197-
const api::Permissions &perms) -> api::WrapperResponse {
196+
const http::request<http::string_body> &request,
197+
const api::Permissions &perms,
198+
const api::RouteCB &cb) {
198199
if (not primitives::jwt::hasPermission(
199200
perms, primitives::jwt::kAdminPermission)) {
200-
return api::makeErrorResponse(request, http::status::unauthorized);
201+
return cb(api::makeErrorResponse(request, http::status::unauthorized));
201202
}
202203

203204
std::regex stat_rgx(R"(\/remote\/stat\/([\w-]+))");
@@ -210,27 +211,27 @@ namespace fc::sector_storage {
210211
case http::verb::get:
211212
if (std::regex_search(
212213
target.cbegin(), target.cend(), matches, stat_rgx)) {
213-
return remoteStatFs(request, local, logger, matches[1]);
214+
return cb(remoteStatFs(request, local, logger, matches[1]));
214215
} else if (std::regex_search(
215216
target.cbegin(), target.cend(), matches, sector_rgx)) {
216-
return remoteGetSector(
217-
request, local, logger, matches[1], matches[2]);
217+
return cb(remoteGetSector(
218+
request, local, logger, matches[1], matches[2]));
218219
} else {
219-
return api::makeErrorResponse(request,
220-
http::status::internal_server_error);
220+
return cb(api::makeErrorResponse(
221+
request, http::status::internal_server_error));
221222
}
222223
case http::verb::delete_:
223224
if (std::regex_search(
224225
target.cbegin(), target.cend(), matches, sector_rgx)) {
225-
return remoteRemoveSector(
226-
request, local, logger, matches[1], matches[2]);
226+
return cb(remoteRemoveSector(
227+
request, local, logger, matches[1], matches[2]));
227228
} else {
228-
return api::makeErrorResponse(request,
229-
http::status::internal_server_error);
229+
return cb(api::makeErrorResponse(
230+
request, http::status::internal_server_error));
230231
}
231232
default:
232-
return api::makeErrorResponse(request,
233-
http::status::method_not_allowed);
233+
return cb(api::makeErrorResponse(request,
234+
http::status::method_not_allowed));
234235
}
235236
};
236237
}

0 commit comments

Comments
 (0)