From 6d4f9c4ee8cf8003a1ef4f567506bd21b384629e Mon Sep 17 00:00:00 2001 From: Wu Tao Date: Wed, 9 Sep 2020 16:28:11 +0800 Subject: [PATCH] refactor(http): add http handler without creating http service (#615) --- .../dsn/dist/replication/meta_service_app.h | 1 - .../replication/replication_service_app.h | 4 - include/dsn/http/http_server.h | 30 +++++++- src/http/builtin_http_calls.cpp | 77 +++++++++++++++++++ src/http/builtin_http_calls.h | 35 +++++++++ src/http/http_server.cpp | 26 ++++--- src/http/perf_counter_http_service.cpp | 5 +- src/http/perf_counter_http_service.h | 28 ------- src/http/pprof_http_service.cpp | 2 + src/http/root_http_service.h | 43 ----------- src/http/server_info_http_services.cpp | 38 --------- src/http/server_info_http_services.h | 55 ------------- src/http/test/http_server_test.cpp | 26 ++++--- .../test/perf_counter_http_service_test.cpp | 13 +--- src/meta/meta_service_app.cpp | 12 --- src/replica/replication_service_app.cpp | 13 +--- 16 files changed, 181 insertions(+), 227 deletions(-) create mode 100644 src/http/builtin_http_calls.cpp create mode 100644 src/http/builtin_http_calls.h delete mode 100644 src/http/perf_counter_http_service.h delete mode 100644 src/http/root_http_service.h delete mode 100644 src/http/server_info_http_services.cpp delete mode 100644 src/http/server_info_http_services.h diff --git a/include/dsn/dist/replication/meta_service_app.h b/include/dsn/dist/replication/meta_service_app.h index 676bcacb30..0777f31965 100644 --- a/include/dsn/dist/replication/meta_service_app.h +++ b/include/dsn/dist/replication/meta_service_app.h @@ -59,7 +59,6 @@ class meta_service_app : public service_app private: friend class ::dsn::replication::test::test_checker; std::unique_ptr _service; - version_http_service *_version_http_service; }; } // namespace service } // namespace dsn diff --git a/include/dsn/dist/replication/replication_service_app.h b/include/dsn/dist/replication/replication_service_app.h index b7e5fe3765..e6e98eac7f 100644 --- a/include/dsn/dist/replication/replication_service_app.h +++ b/include/dsn/dist/replication/replication_service_app.h @@ -70,10 +70,6 @@ class replication_service_app : public ::dsn::service_app private: friend class ::dsn::replication::test::test_checker; replica_stub_ptr _stub; - version_http_service *_version_http_service; - - static const char *replica_service_app_info(int argc, char **argv); - static void replica_service_app_info_free(const char *response); }; } // namespace replication } // namespace dsn diff --git a/include/dsn/http/http_server.h b/include/dsn/http/http_server.h index a369d6661e..2d9418937b 100644 --- a/include/dsn/http/http_server.h +++ b/include/dsn/http/http_server.h @@ -4,9 +4,6 @@ #pragma once -#include -#include -#include #include #include @@ -20,6 +17,7 @@ enum http_method HTTP_METHOD_POST = 2, }; +class message_ex; struct http_request { static error_with parse(dsn::message_ex *m); @@ -59,6 +57,17 @@ struct http_call std::string path; std::string help; http_callback callback; + + http_call &with_callback(http_callback cb) + { + callback = std::move(cb); + return *this; + } + http_call &with_help(std::string hp) + { + help = std::move(hp); + return *this; + } }; // A suite of HTTP handlers coupled using the same prefix of the service. @@ -74,11 +83,24 @@ class http_service void register_handler(std::string path, http_callback cb, std::string help); }; +// Example: +// +// ``` +// register_http_call("/meta/app") +// .with_callback(std::bind(&meta_http_service::get_app_handler, +// this, +// std::placeholders::_1, +// std::placeholders::_2)) +// .with_help("Gets the app information") +// .add_argument("app_name", HTTP_ARG_STRING); +// ``` +extern http_call ®ister_http_call(std::string full_path); + // Starts serving HTTP requests. // The internal HTTP server will reuse the rDSN server port. extern void start_http_server(); -// NOTE: the memory of `svc` will be transfered to the underlying registry. +// NOTE: the memory of `svc` will be transferred to the underlying registry. // TODO(wutao): pass `svc` as a std::unique_ptr. extern void register_http_service(http_service *svc); diff --git a/src/http/builtin_http_calls.cpp b/src/http/builtin_http_calls.cpp new file mode 100644 index 0000000000..d8dae85147 --- /dev/null +++ b/src/http/builtin_http_calls.cpp @@ -0,0 +1,77 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#include +#include + +#include "builtin_http_calls.h" +#include "http_call_registry.h" +#include "pprof_http_service.h" + +namespace dsn { + +/*extern*/ void get_help_handler(const http_request &req, http_response &resp) +{ + utils::table_printer tp; + std::ostringstream oss; + auto calls = http_call_registry::instance().list_all_calls(); + for (const auto &call : calls) { + tp.add_row_name_and_data(std::string("/") + call->path, call->help); + } + tp.output(oss, utils::table_printer::output_format::kJsonCompact); + resp.body = oss.str(); + resp.status_code = http_status_code::ok; +} + +/*extern*/ void get_recent_start_time_handler(const http_request &req, http_response &resp) +{ + char start_time[100]; + dsn::utils::time_ms_to_date_time(dsn::utils::process_start_millis(), start_time, 100); + std::ostringstream out; + dsn::utils::table_printer tp; + tp.add_row_name_and_data("RecentStartTime", start_time); + tp.output(out, dsn::utils::table_printer::output_format::kJsonCompact); + + resp.body = out.str(); + resp.status_code = http_status_code::ok; +} + +/*extern*/ void register_builtin_http_calls() +{ +#ifdef DSN_ENABLE_GPERF + static pprof_http_service pprof_svc; +#endif + + register_http_call("") + .with_callback( + [](const http_request &req, http_response &resp) { get_help_handler(req, resp); }) + .with_help("Lists all supported calls"); + + register_http_call("recentStartTime") + .with_callback([](const http_request &req, http_response &resp) { + get_recent_start_time_handler(req, resp); + }) + .with_help("Gets the server start time."); + + register_http_call("perfCounter") + .with_callback([](const http_request &req, http_response &resp) { + get_perf_counter_handler(req, resp); + }) + .with_help("Gets the value of a perf counter"); +} + +} // namespace dsn diff --git a/src/http/builtin_http_calls.h b/src/http/builtin_http_calls.h new file mode 100644 index 0000000000..2cb190a35f --- /dev/null +++ b/src/http/builtin_http_calls.h @@ -0,0 +1,35 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#pragma once + +#include +#include +#include + +namespace dsn { + +// Register basic services for the HTTP server. +extern void register_builtin_http_calls(); + +extern void get_perf_counter_handler(const http_request &req, http_response &resp); + +extern void get_help_handler(const http_request &req, http_response &resp); + +extern void get_recent_start_time_handler(const http_request &req, http_response &resp); + +} // namespace dsn diff --git a/src/http/http_server.cpp b/src/http/http_server.cpp index 4eb761b31e..97ee556d59 100644 --- a/src/http/http_server.cpp +++ b/src/http/http_server.cpp @@ -4,13 +4,13 @@ #include #include +#include #include #include #include "http_message_parser.h" -#include "root_http_service.h" #include "pprof_http_service.h" -#include "perf_counter_http_service.h" +#include "builtin_http_calls.h" #include "uri_decoder.h" #include "http_call_registry.h" #include "http_server_impl.h" @@ -38,6 +38,20 @@ DSN_DEFINE_bool("http", enable_http_server, true, "whether to enable the embedde } } +/*extern*/ http_call ®ister_http_call(std::string full_path) +{ + auto call_ptr = dsn::make_unique(); + call_ptr->path = std::move(full_path); + http_call &call = *call_ptr; + http_call_registry::instance().add(std::move(call_ptr)); + return call; +} + +/*extern*/ void deregister_http_call(const std::string &full_path) +{ + http_call_registry::instance().remove(full_path); +} + void http_service::register_handler(std::string path, http_callback cb, std::string help) { if (!FLAGS_enable_http_server) { @@ -64,13 +78,7 @@ http_server::http_server() : serverlet("http_server") tools::register_message_header_parser(NET_HDR_HTTP, {"GET ", "POST"}); // add builtin services - register_http_service(new root_http_service()); - -#ifdef DSN_ENABLE_GPERF - register_http_service(new pprof_http_service()); -#endif // DSN_ENABLE_GPERF - - register_http_service(new perf_counter_http_service()); + register_builtin_http_calls(); } void http_server::serve(message_ex *msg) diff --git a/src/http/perf_counter_http_service.cpp b/src/http/perf_counter_http_service.cpp index 0b8c5b4c5c..d9d1e81a84 100644 --- a/src/http/perf_counter_http_service.cpp +++ b/src/http/perf_counter_http_service.cpp @@ -3,12 +3,11 @@ // can be found in the LICENSE file in the root directory of this source tree. #include -#include "perf_counter_http_service.h" +#include "builtin_http_calls.h" namespace dsn { -void perf_counter_http_service::get_perf_counter_handler(const http_request &req, - http_response &resp) +void get_perf_counter_handler(const http_request &req, http_response &resp) { std::string perf_counter_name; for (const auto &p : req.query_args) { diff --git a/src/http/perf_counter_http_service.h b/src/http/perf_counter_http_service.h deleted file mode 100644 index 691925a898..0000000000 --- a/src/http/perf_counter_http_service.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2017-present, Xiaomi, Inc. All rights reserved. -// This source code is licensed under the Apache License Version 2.0, which -// can be found in the LICENSE file in the root directory of this source tree. - -#pragma once - -#include - -namespace dsn { - -class perf_counter_http_service : public http_service -{ -public: - perf_counter_http_service() - { - register_handler("", - std::bind(&perf_counter_http_service::get_perf_counter_handler, - this, - std::placeholders::_1, - std::placeholders::_2), - "ip:port/perfCounter?name={perf_counter_name}"); - } - - std::string path() const override { return "perfCounter"; } - - void get_perf_counter_handler(const http_request &req, http_response &resp); -}; -} // namespace dsn diff --git a/src/http/pprof_http_service.cpp b/src/http/pprof_http_service.cpp index 250158fce8..4cce6eef19 100644 --- a/src/http/pprof_http_service.cpp +++ b/src/http/pprof_http_service.cpp @@ -26,6 +26,8 @@ #include "pprof_http_service.h" #include +#include +#include #include #include #include diff --git a/src/http/root_http_service.h b/src/http/root_http_service.h deleted file mode 100644 index 73a2ea5044..0000000000 --- a/src/http/root_http_service.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2018, Xiaomi, Inc. All rights reserved. -// This source code is licensed under the Apache License Version 2.0, which -// can be found in the LICENSE file in the root directory of this source tree. - -#include -#include -#include - -#include "http_call_registry.h" - -namespace dsn { - -class root_http_service : public http_service -{ -public: - explicit root_http_service() - { - // url: ip:port/ - register_handler("", - std::bind(&root_http_service::default_handler, - this, - std::placeholders::_1, - std::placeholders::_2), - "ip:port/"); - } - - std::string path() const override { return ""; } - - void default_handler(const http_request &req, http_response &resp) - { - utils::table_printer tp; - std::ostringstream oss; - auto calls = http_call_registry::instance().list_all_calls(); - for (const auto &call : calls) { - tp.add_row_name_and_data(std::string("/") + call->path, call->help); - } - tp.output(oss, utils::table_printer::output_format::kJsonCompact); - resp.body = oss.str(); - resp.status_code = http_status_code::ok; - } -}; - -} // namespace dsn diff --git a/src/http/server_info_http_services.cpp b/src/http/server_info_http_services.cpp deleted file mode 100644 index 1f2013254d..0000000000 --- a/src/http/server_info_http_services.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2017-present, Xiaomi, Inc. All rights reserved. -// This source code is licensed under the Apache License Version 2.0, which -// can be found in the LICENSE file in the root directory of this source tree. - -#include -#include - -#include "server_info_http_services.h" - -namespace dsn { - -void version_http_service::get_version_handler(const http_request &req, http_response &resp) -{ - std::ostringstream out; - dsn::utils::table_printer tp; - tp.add_row_name_and_data("Version", _version); - tp.add_row_name_and_data("GitCommit", _git_commit); - tp.output(out, dsn::utils::table_printer::output_format::kJsonCompact); - - resp.body = out.str(); - resp.status_code = http_status_code::ok; -} - -void recent_start_time_http_service::get_recent_start_time_handler(const http_request &req, - http_response &resp) -{ - char start_time[100]; - dsn::utils::time_ms_to_date_time(dsn::utils::process_start_millis(), start_time, 100); - std::ostringstream out; - dsn::utils::table_printer tp; - tp.add_row_name_and_data("RecentStartTime", start_time); - tp.output(out, dsn::utils::table_printer::output_format::kJsonCompact); - - resp.body = out.str(); - resp.status_code = http_status_code::ok; -} - -} // namespace dsn diff --git a/src/http/server_info_http_services.h b/src/http/server_info_http_services.h deleted file mode 100644 index 04e7eede92..0000000000 --- a/src/http/server_info_http_services.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2017-present, Xiaomi, Inc. All rights reserved. -// This source code is licensed under the Apache License Version 2.0, which -// can be found in the LICENSE file in the root directory of this source tree. - -#pragma once - -#include - -namespace dsn { - -class version_http_service : public http_service -{ -public: - version_http_service() - { - register_handler("", - std::bind(&version_http_service::get_version_handler, - this, - std::placeholders::_1, - std::placeholders::_2), - "ip:port/version"); - } - - std::string path() const override { return "version"; } - - void get_version_handler(const http_request &req, http_response &resp); - - void set_version(const std::string &ver) { _version = ver; } - - void set_git_commit(const std::string &git) { _git_commit = git; } - -private: - std::string _version; - std::string _git_commit; -}; - -class recent_start_time_http_service : public http_service -{ -public: - recent_start_time_http_service() - { - register_handler("", - std::bind(&recent_start_time_http_service::get_recent_start_time_handler, - this, - std::placeholders::_1, - std::placeholders::_2), - "ip:port/recentStartTime"); - } - - std::string path() const override { return "recentStartTime"; } - - void get_recent_start_time_handler(const http_request &req, http_response &resp); -}; - -} // namespace dsn diff --git a/src/http/test/http_server_test.cpp b/src/http/test/http_server_test.cpp index 00b5bf93f4..768621eb2c 100644 --- a/src/http/test/http_server_test.cpp +++ b/src/http/test/http_server_test.cpp @@ -6,9 +6,8 @@ #include #include "http/http_message_parser.h" -#include "http/root_http_service.h" -#include "http/server_info_http_services.h" -#include "http/http_server_impl.h" +#include "http/builtin_http_calls.h" +#include "http/http_call_registry.h" namespace dsn { @@ -46,22 +45,31 @@ TEST(http_server, parse_url) } } -TEST(root_http_service_test, get_help) +TEST(bultin_http_calls_test, get_help) { for (const auto &call : http_call_registry::instance().list_all_calls()) { http_call_registry::instance().remove(call->path); } - root_http_service root; + register_http_call("") + .with_callback( + [](const http_request &req, http_response &resp) { get_help_handler(req, resp); }) + .with_help("ip:port/"); + http_request req; http_response resp; - root.default_handler(req, resp); + get_help_handler(req, resp); ASSERT_EQ(resp.status_code, http_status_code::ok); ASSERT_EQ(resp.body, "{\"/\":\"ip:port/\"}\n"); - version_http_service ver; - root.default_handler(req, resp); - ASSERT_EQ(resp.body, "{\"/\":\"ip:port/\",\"/version\":\"ip:port/version\"}\n"); + register_http_call("recentStartTime") + .with_callback([](const http_request &req, http_response &resp) { + get_recent_start_time_handler(req, resp); + }) + .with_help("ip:port/recentStartTime"); + + get_help_handler(req, resp); + ASSERT_EQ(resp.body, "{\"/\":\"ip:port/\",\"/recentStartTime\":\"ip:port/recentStartTime\"}\n"); for (const auto &call : http_call_registry::instance().list_all_calls()) { http_call_registry::instance().remove(call->path); diff --git a/src/http/test/perf_counter_http_service_test.cpp b/src/http/test/perf_counter_http_service_test.cpp index 6dbb788a5e..4c6b2ec86d 100644 --- a/src/http/test/perf_counter_http_service_test.cpp +++ b/src/http/test/perf_counter_http_service_test.cpp @@ -5,17 +5,12 @@ #include #include #include -#include -namespace dsn { +#include "http/builtin_http_calls.h" -class perf_counter_http_service_test : public testing::Test -{ -public: - perf_counter_http_service _perf_counter_http_service; -}; +namespace dsn { -TEST_F(perf_counter_http_service_test, get_perf_counter) +TEST(perf_counter_http_service_test, get_perf_counter) { struct test_case { @@ -42,7 +37,7 @@ TEST_F(perf_counter_http_service_test, get_perf_counter) http_request fake_req; http_response fake_resp; fake_req.query_args.emplace("name", perf_counter_name); - _perf_counter_http_service.get_perf_counter_handler(fake_req, fake_resp); + get_perf_counter_handler(fake_req, fake_resp); // get fake json based on the perf counter info which is getting above std::string fake_json; diff --git a/src/meta/meta_service_app.cpp b/src/meta/meta_service_app.cpp index 1a20104cf4..aaec4e5faa 100644 --- a/src/meta/meta_service_app.cpp +++ b/src/meta/meta_service_app.cpp @@ -32,7 +32,6 @@ #include "distributed_lock_service_simple.h" #include "meta_state_service_simple.h" -#include "http/server_info_http_services.h" #include "zookeeper/distributed_lock_service_zookeeper.h" #include "meta_state_service_zookeeper.h" @@ -87,10 +86,7 @@ meta_service_app::meta_service_app(const service_app_info *info) : service_app(i _service.reset(new replication::meta_service()); // add http service - _version_http_service = new version_http_service(); register_http_service(new replication::meta_http_service(_service.get())); - register_http_service(new recent_start_time_http_service()); - register_http_service(_version_http_service); start_http_server(); } @@ -98,14 +94,6 @@ meta_service_app::~meta_service_app() {} error_code meta_service_app::start(const std::vector &args) { - // TODO: handle the load & restore - // set args of http service - if (args.size() >= 2) { - auto it_ver = args.end() - 2; - auto it_git = args.end() - 1; - _version_http_service->set_version(*it_ver); - _version_http_service->set_git_commit(*it_git); - } return _service->start(); } diff --git a/src/replica/replication_service_app.cpp b/src/replica/replication_service_app.cpp index cddd96f640..3490882f4f 100644 --- a/src/replica/replication_service_app.cpp +++ b/src/replica/replication_service_app.cpp @@ -28,7 +28,6 @@ #include #include "common/replication_common.h" -#include "http/server_info_http_services.h" #include "replica_stub.h" #include "replica_http_service.h" @@ -45,10 +44,8 @@ replication_service_app::replication_service_app(const service_app_info *info) : _stub = new replica_stub(); // add http service - _version_http_service = new version_http_service(); - register_http_service(_version_http_service); - register_http_service(new recent_start_time_http_service()); register_http_service(new replica_http_service(_stub.get())); + start_http_server(); } replication_service_app::~replication_service_app(void) {} @@ -61,14 +58,6 @@ error_code replication_service_app::start(const std::vector &args) _stub->initialize(opts); _stub->open_service(); - // add http service - if (args.size() >= 2) { - auto it_ver = args.end() - 2; - auto it_git = args.end() - 1; - _version_http_service->set_version(*it_ver); - _version_http_service->set_git_commit(*it_git); - } - return ERR_OK; }