Skip to content

Commit

Permalink
Merge pull request #9633 from EOSIO/conr2d-allow-empty-response
Browse files Browse the repository at this point in the history
Allow HTTP-RPC with empty response
  • Loading branch information
heifner committed Jul 9, 2022
1 parent d786299 commit e5b8ac9
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 29 deletions.
69 changes: 45 additions & 24 deletions plugins/http_plugin/http_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ namespace eosio {

static http_plugin_defaults current_http_plugin_defaults;

void http_plugin::set_defaults(const http_plugin_defaults config) {
void http_plugin::set_defaults(const http_plugin_defaults& config) {
current_http_plugin_defaults = config;
}

Expand Down Expand Up @@ -128,11 +128,11 @@ namespace eosio {
* virtualized wrapper for the various underlying connection functions needed in req/resp processng
*/
struct abstract_conn {
virtual ~abstract_conn() {}
virtual ~abstract_conn() = default;
virtual bool verify_max_bytes_in_flight() = 0;
virtual bool verify_max_requests_in_flight() = 0;
virtual void handle_exception() = 0;
virtual void send_response(std::string, int) = 0;
virtual void send_response(std::optional<std::string> body, int code) = 0;
};

using abstract_conn_ptr = std::shared_ptr<abstract_conn>;
Expand Down Expand Up @@ -167,6 +167,21 @@ namespace eosio {
} catch(...) {}
return 0;
}

/**
* Helper method to calculate the "in flight" size of a std::optional<T>
* When the optional doesn't contain value, it will return the size of 0
*
* @param o - the std::optional<T> where T is typename
* @return in flight size of o
*/
template<typename T>
static size_t in_flight_sizeof( const std::optional<T>& o ) {
if( o ) {
return in_flight_sizeof( *o );
}
return 0;
}
}

using websocket_server_type = websocketpp::server<detail::asio_with_stub_log<websocketpp::transport::asio::basic_socket::endpoint>>;
Expand Down Expand Up @@ -238,7 +253,7 @@ class http_plugin_impl : public std::enable_shared_from_this<http_plugin_impl> {
}
}

ssl_context_ptr on_tls_init(websocketpp::connection_hdl hdl) {
ssl_context_ptr on_tls_init() {
ssl_context_ptr ctx = websocketpp::lib::make_shared<websocketpp::lib::asio::ssl::context>(asio::ssl::context::sslv23_server);

try {
Expand Down Expand Up @@ -383,7 +398,7 @@ class http_plugin_impl : public std::enable_shared_from_this<http_plugin_impl> {
_impl->requests_in_flight += 1;
}

~abstract_conn_impl() {
~abstract_conn_impl() override {
_impl->requests_in_flight -= 1;
}

Expand All @@ -405,8 +420,10 @@ class http_plugin_impl : public std::enable_shared_from_this<http_plugin_impl> {
http_plugin_impl::handle_exception<T>(_conn);
}

void send_response(std::string body, int code) override {
_conn->set_body(std::move(body));
void send_response(std::optional<std::string> body, int code) override {
if( body ) {
_conn->set_body( std::move( *body ) );
}
_conn->set_status( websocketpp::http::status_code::value( code ) );
_conn->send_http_response();
}
Expand Down Expand Up @@ -472,15 +489,15 @@ class http_plugin_impl : public std::enable_shared_from_this<http_plugin_impl> {
* const accessor
* @return const reference to the contained object
*/
const T& operator* () const {
const T& obj() const {
return _object;
}

/**
* mutable accessor (can be moved frmo)
* mutable accessor (can be moved from)
* @return mutable reference to the contained object
*/
T& operator* () {
T& obj() {
return _object;
}

Expand Down Expand Up @@ -516,7 +533,7 @@ class http_plugin_impl : public std::enable_shared_from_this<http_plugin_impl> {
return;
}

url_response_callback wrapped_then = [tracked_b, then=std::move(then)](int code, fc::variant resp) {
url_response_callback wrapped_then = [tracked_b, then=std::move(then)](int code, std::optional<fc::variant> resp) {
then(code, std::move(resp));
};

Expand All @@ -525,7 +542,7 @@ class http_plugin_impl : public std::enable_shared_from_this<http_plugin_impl> {
app().post( priority, [next_ptr, conn=std::move(conn), r=std::move(r), tracked_b, wrapped_then=std::move(wrapped_then)]() mutable {
try {
// call the `next` url_handler and wrap the response handler
(*next_ptr)( std::move( r ), std::move(*(*tracked_b)), std::move(wrapped_then)) ;
(*next_ptr)( std::move( r ), std::move(tracked_b->obj()), std::move(wrapped_then)) ;
} catch( ... ) {
conn->handle_exception();
}
Expand All @@ -541,7 +558,7 @@ class http_plugin_impl : public std::enable_shared_from_this<http_plugin_impl> {
* @return the constructed internal_url_handler
*/
static detail::internal_url_handler make_http_thread_url_handler(url_handler next) {
return [next=std::move(next)]( detail::abstract_conn_ptr conn, string r, string b, url_response_callback then ) {
return [next=std::move(next)]( const detail::abstract_conn_ptr& conn, string r, string b, url_response_callback then ) {
try {
next(std::move(r), std::move(b), std::move(then));
} catch( ... ) {
Expand All @@ -558,8 +575,8 @@ class http_plugin_impl : public std::enable_shared_from_this<http_plugin_impl> {
* @return lambda suitable for url_response_callback
*/
template<typename T>
auto make_http_response_handler( detail::abstract_conn_ptr abstract_conn_ptr) {
return [my=shared_from_this(), abstract_conn_ptr]( int code, fc::variant response ) {
auto make_http_response_handler( const detail::abstract_conn_ptr& abstract_conn_ptr) {
return [my=shared_from_this(), abstract_conn_ptr]( int code, std::optional<fc::variant> response ) {
auto tracked_response = make_in_flight(std::move(response), my);
if (!abstract_conn_ptr->verify_max_bytes_in_flight()) {
return;
Expand All @@ -569,9 +586,13 @@ class http_plugin_impl : public std::enable_shared_from_this<http_plugin_impl> {
boost::asio::post( my->thread_pool->get_executor(),
[my, abstract_conn_ptr, code, tracked_response=std::move(tracked_response)]() {
try {
std::string json = fc::json::to_string( *(*tracked_response), fc::time_point::now() + my->max_response_time );
auto tracked_json = make_in_flight(std::move(json), my);
abstract_conn_ptr->send_response(std::move(*(*tracked_json)), code);
if( tracked_response->obj().has_value() ) {
std::string json = fc::json::to_string( *tracked_response->obj(), fc::time_point::now() + my->max_response_time );
auto tracked_json = make_in_flight( std::move( json ), my );
abstract_conn_ptr->send_response( std::move( tracked_json->obj() ), code );
} else {
abstract_conn_ptr->send_response( {}, code );
}
} catch( ... ) {
abstract_conn_ptr->handle_exception();
}
Expand Down Expand Up @@ -649,7 +670,7 @@ class http_plugin_impl : public std::enable_shared_from_this<http_plugin_impl> {
}
}

void add_aliases_for_endpoint( const tcp::endpoint& ep, string host, string port ) {
void add_aliases_for_endpoint( const tcp::endpoint& ep, const string& host, const string& port ) {
auto resolved_port_str = std::to_string(ep.port());
valid_hosts.emplace(host + ":" + port);
valid_hosts.emplace(host + ":" + resolved_port_str);
Expand All @@ -664,7 +685,7 @@ class http_plugin_impl : public std::enable_shared_from_this<http_plugin_impl> {
http_plugin::http_plugin():my(new http_plugin_impl()){
app().register_config_type<https_ecdh_curve_t>();
}
http_plugin::~http_plugin(){}
http_plugin::~http_plugin() = default;

void http_plugin::set_program_options(options_description&, options_description& cfg) {
if(current_http_plugin_defaults.default_unix_socket_path.length())
Expand Down Expand Up @@ -861,7 +882,7 @@ class http_plugin_impl : public std::enable_shared_from_this<http_plugin_impl> {
my->unix_server.listen(*my->unix_endpoint);
// captures `this`, my needs to live as long as unix_server is handling requests
my->unix_server.set_http_handler([this](connection_hdl hdl) {
my->handle_http_request<detail::asio_local_with_stub_log>( my->unix_server.get_con_from_hdl(hdl));
my->handle_http_request<detail::asio_local_with_stub_log>( my->unix_server.get_con_from_hdl(std::move(hdl)));
});
my->unix_server.start_accept();
} catch ( const fc::exception& e ){
Expand All @@ -879,8 +900,8 @@ class http_plugin_impl : public std::enable_shared_from_this<http_plugin_impl> {
if(my->https_listen_endpoint) {
try {
my->create_server_for_endpoint(*my->https_listen_endpoint, my->https_server);
my->https_server.set_tls_init_handler([this](websocketpp::connection_hdl hdl) -> ssl_context_ptr{
return my->on_tls_init(hdl);
my->https_server.set_tls_init_handler([this](const websocketpp::connection_hdl& hdl) -> ssl_context_ptr{
return my->on_tls_init();
});

fc_ilog( logger, "start listening for https requests" );
Expand All @@ -900,7 +921,7 @@ class http_plugin_impl : public std::enable_shared_from_this<http_plugin_impl> {

add_api({{
std::string("/v1/node/get_supported_apis"),
[&](string, string body, url_response_callback cb) mutable {
[&](const string&, string body, url_response_callback cb) mutable {
try {
if (body.empty()) body = "{}";
auto result = (*this).get_supported_apis();
Expand Down
10 changes: 5 additions & 5 deletions plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace eosio {
*
* Arguments: response_code, response_body
*/
using url_response_callback = std::function<void(int,fc::variant)>;
using url_response_callback = std::function<void(int,std::optional<fc::variant>)>;

/**
* @brief Callback type for a URL handler
Expand Down Expand Up @@ -65,13 +65,13 @@ namespace eosio {
{
public:
http_plugin();
virtual ~http_plugin();
~http_plugin() override;

//must be called before initialize
static void set_defaults(const http_plugin_defaults config);
static void set_defaults(const http_plugin_defaults& config);

APPBASE_PLUGIN_REQUIRES()
virtual void set_program_options(options_description&, options_description& cfg) override;
void set_program_options(options_description&, options_description& cfg) override;

void plugin_initialize(const variables_map& options);
void plugin_startup();
Expand Down Expand Up @@ -134,7 +134,7 @@ namespace eosio {

static const uint8_t details_limit = 10;

error_info() {};
error_info() = default;

error_info(const fc::exception& exc, bool include_full_log) {
code = exc.code();
Expand Down

0 comments on commit e5b8ac9

Please sign in to comment.