Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
sysio::http_plugin_impl Class Reference
Inheritance diagram for sysio::http_plugin_impl:
Collaboration diagram for sysio::http_plugin_impl:

Classes

struct  abstract_conn_impl
 
struct  in_flight
 

Public Member Functions

 http_plugin_impl ()=default
 
 http_plugin_impl (const http_plugin_impl &)=delete
 
 http_plugin_impl (http_plugin_impl &&)=delete
 
http_plugin_imploperator= (const http_plugin_impl &)=delete
 
http_plugin_imploperator= (http_plugin_impl &&)=delete
 
bool host_port_is_valid (const std::string &header_host_port, const string &endpoint_local_host_port)
 
bool host_is_valid (const std::string &host, const string &endpoint_local_host_port, bool secure)
 
ssl_context_ptr on_tls_init (websocketpp::connection_hdl hdl)
 
template<class T >
bool allow_host (const typename T::request_type &req, detail::connection_ptr< T > con)
 
template<typename T >
bool verify_max_bytes_in_flight (const T &con)
 
template<typename T >
auto make_http_response_handler (detail::abstract_conn_ptr abstract_conn_ptr)
 
template<class T >
void handle_http_request (detail::connection_ptr< T > con)
 
template<class T >
void create_server_for_endpoint (const tcp::endpoint &ep, websocketpp::server< detail::asio_with_stub_log< T > > &ws)
 
void add_aliases_for_endpoint (const tcp::endpoint &ep, string host, string port)
 

Static Public Member Functions

template<class T >
static void handle_exception (detail::connection_ptr< T > con)
 
template<typename T >
static detail::abstract_conn_ptr make_abstract_conn_ptr (detail::connection_ptr< T > conn, http_plugin_impl_ptr impl)
 
template<typename T >
static auto make_in_flight (T &&object, http_plugin_impl_ptr impl)
 
static detail::internal_url_handler make_app_thread_url_handler (int priority, url_handler next, http_plugin_impl_ptr my)
 
static detail::internal_url_handler make_http_thread_url_handler (url_handler next)
 

Public Attributes

map< string, detail::internal_url_handlerurl_handlers
 
std::optional< tcp::endpoint > listen_endpoint
 
string access_control_allow_origin
 
string access_control_allow_headers
 
string access_control_max_age
 
bool access_control_allow_credentials = false
 
size_t max_body_size {2*1024*1024}
 
websocket_server_type server
 
uint16_t thread_pool_size = 2
 
std::optional< sysio::chain::named_thread_poolthread_pool
 
std::atomic< size_t > bytes_in_flight {0}
 
size_t max_bytes_in_flight = 0
 
fc::microseconds max_response_time {30*1000}
 
std::optional< tcp::endpoint > https_listen_endpoint
 
string https_cert_chain
 
string https_key
 
https_ecdh_curve_t https_ecdh_curve = SECP384R1
 
websocket_server_tls_type https_server
 
std::optional< asio::local::stream_protocol::endpoint > unix_endpoint
 
websocket_local_server_type unix_server
 
bool validate_host = true
 
set< stringvalid_hosts
 

Detailed Description

Definition at line 179 of file http_plugin.cpp.

Constructor & Destructor Documentation

◆ http_plugin_impl() [1/3]

sysio::http_plugin_impl::http_plugin_impl ( )
default

◆ http_plugin_impl() [2/3]

sysio::http_plugin_impl::http_plugin_impl ( const http_plugin_impl & )
delete

◆ http_plugin_impl() [3/3]

sysio::http_plugin_impl::http_plugin_impl ( http_plugin_impl && )
delete

Member Function Documentation

◆ add_aliases_for_endpoint()

void sysio::http_plugin_impl::add_aliases_for_endpoint ( const tcp::endpoint & ep,
string host,
string port )
inline

Definition at line 620 of file http_plugin.cpp.

620 {
621 auto resolved_port_str = std::to_string(ep.port());
622 valid_hosts.emplace(host + ":" + port);
623 valid_hosts.emplace(host + ":" + resolved_port_str);
624 }

◆ allow_host()

template<class T >
bool sysio::http_plugin_impl::allow_host ( const typename T::request_type & req,
detail::connection_ptr< T > con )
inline

Definition at line 315 of file http_plugin.cpp.

315 {
316 bool is_secure = con->get_uri()->get_secure();
317 const auto& local_endpoint = con->get_socket().lowest_layer().local_endpoint();
318 auto local_socket_host_port = local_endpoint.address().to_string() + ":" + std::to_string(local_endpoint.port());
319
320 const auto& host_str = req.get_header("Host");
321 if (host_str.empty() || !host_is_valid(host_str, local_socket_host_port, is_secure)) {
323 return false;
324 }
325 return true;
326 }
bool host_is_valid(const std::string &host, const string &endpoint_local_host_port, bool secure)
Here is the call graph for this function:

◆ create_server_for_endpoint()

template<class T >
void sysio::http_plugin_impl::create_server_for_endpoint ( const tcp::endpoint & ep,
websocketpp::server< detail::asio_with_stub_log< T > > & ws )
inline

Definition at line 601 of file http_plugin.cpp.

601 {
602 try {
603 ws.clear_access_channels(websocketpp::log::alevel::all);
604 ws.init_asio( &thread_pool->get_executor() );
605 ws.set_reuse_addr(true);
606 ws.set_max_http_body_size(max_body_size);
607 // captures `this` & ws, my needs to live as long as server is handling requests
608 ws.set_http_handler([&](connection_hdl hdl) {
610 });
611 } catch ( const fc::exception& e ){
612 fc_elog( logger, "http: ${e}", ("e", e.to_detail_string()) );
613 } catch ( const std::exception& e ){
614 fc_elog( logger, "http: ${e}", ("e", e.what()) );
615 } catch (...) {
616 fc_elog( logger, "error thrown from http io service" );
617 }
618 }
std::string ws(int const level)
Used to generate a useful error report when an exception is thrown.
Definition exception.hpp:58
std::string to_detail_string(log_level ll=log_level::all) const
std::optional< sysio::chain::named_thread_pool > thread_pool
void handle_http_request(detail::connection_ptr< T > con)
#define fc_elog(LOGGER, FORMAT,...)
Definition logger.hpp:95
fc::logger logger
lib::weak_ptr< void > connection_hdl
A handle to uniquely identify a connection.
static level const all
Special aggregate value representing "all levels".
Definition levels.hpp:152
Here is the call graph for this function:

◆ handle_exception()

template<class T >
static void sysio::http_plugin_impl::handle_exception ( detail::connection_ptr< T > con)
inlinestatic

Definition at line 274 of file http_plugin.cpp.

274 {
275 string err = "Internal Service error, http: ";
277 try {
279 try {
280 throw;
281 } catch (const fc::exception& e) {
282 err += e.to_detail_string();
283 fc_elog( logger, "${e}", ("e", err));
285 "Internal Service Error", error_results::error_info( e, verbose_http_errors )};
286 con->set_body( fc::json::to_string( results, deadline ));
287 } catch (const std::exception& e) {
288 err += e.what();
289 fc_elog( logger, "${e}", ("e", err));
291 "Internal Service Error",
292 error_results::error_info( fc::exception( FC_LOG_MESSAGE( error, e.what())),
293 verbose_http_errors )};
294 con->set_body( fc::json::to_string( results, deadline ));
295 } catch (...) {
296 err += "Unknown Exception";
298 "Internal Service Error",
299 error_results::error_info(
300 fc::exception( FC_LOG_MESSAGE( error, "Unknown Exception" )),
301 verbose_http_errors )};
302 con->set_body( fc::json::to_string( results, deadline ));
303 }
304 } catch (fc::timeout_exception& e) {
305 con->set_body( R"xxx({"message": "Internal Server Error"})xxx" );
306 fc_elog( logger, "Timeout exception ${te} attempting to handle exception: ${e}", ("te", e.to_detail_string())("e", err) );
307 } catch (...) {
308 con->set_body( R"xxx({"message": "Internal Server Error"})xxx" );
309 fc_elog( logger, "Exception attempting to handle exception: ${e}", ("e", err) );
310 }
311 con->send_http_response();
312 }
static constexpr fc::microseconds format_time_limit
Definition exception.hpp:60
static string to_string(const variant &v, const yield_function_t &yield, const output_formatting format=output_formatting::stringify_large_ints_and_doubles)
Definition json.cpp:674
static time_point now()
Definition time.cpp:14
#define FC_LOG_MESSAGE(LOG_LEVEL, FORMAT,...)
A helper method for generating log messages.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_http_request()

template<class T >
void sysio::http_plugin_impl::handle_http_request ( detail::connection_ptr< T > con)
inline

Definition at line 551 of file http_plugin.cpp.

551 {
552 try {
553 auto& req = con->get_request();
554
555 if(!allow_host<T>(req, con))
556 return;
557
558 if( !access_control_allow_origin.empty()) {
559 con->append_header( "Access-Control-Allow-Origin", access_control_allow_origin );
560 }
561 if( !access_control_allow_headers.empty()) {
562 con->append_header( "Access-Control-Allow-Headers", access_control_allow_headers );
563 }
564 if( !access_control_max_age.empty()) {
565 con->append_header( "Access-Control-Max-Age", access_control_max_age );
566 }
568 con->append_header( "Access-Control-Allow-Credentials", "true" );
569 }
570
571 if(req.get_method() == "OPTIONS") {
572 con->set_status(websocketpp::http::status_code::ok);
573 return;
574 }
575
576 con->append_header( "Content-type", "application/json" );
577 con->defer_http_response();
578
579 auto abstract_conn_ptr = make_abstract_conn_ptr<T>(con, shared_from_this());
580 if( !verify_max_bytes_in_flight( con )) return;
581
582 std::string resource = con->get_uri()->get_resource();
583 auto handler_itr = url_handlers.find( resource );
584 if( handler_itr != url_handlers.end()) {
585 std::string body = con->get_request_body();
586 handler_itr->second( abstract_conn_ptr, std::move( resource ), std::move( body ), make_http_response_handler<T>(abstract_conn_ptr) );
587 } else {
588 fc_dlog( logger, "404 - not found: ${ep}", ("ep", resource) );
590 "Not Found", error_results::error_info(fc::exception( FC_LOG_MESSAGE( error, "Unknown Endpoint" )), verbose_http_errors )};
593 con->send_http_response();
594 }
595 } catch( ... ) {
596 handle_exception<T>( con );
597 }
598 }
fc::microseconds max_response_time
static void handle_exception(detail::connection_ptr< T > con)
static detail::abstract_conn_ptr make_abstract_conn_ptr(detail::connection_ptr< T > conn, http_plugin_impl_ptr impl)
auto make_http_response_handler(detail::abstract_conn_ptr abstract_conn_ptr)
map< string, detail::internal_url_handler > url_handlers
bool allow_host(const typename T::request_type &req, detail::connection_ptr< T > con)
bool verify_max_bytes_in_flight(const T &con)
#define fc_dlog(LOGGER, FORMAT,...)
Definition logger.hpp:77
std::shared_ptr< abstract_conn > abstract_conn_ptr
Here is the call graph for this function:

◆ host_is_valid()

bool sysio::http_plugin_impl::host_is_valid ( const std::string & host,
const string & endpoint_local_host_port,
bool secure )
inline

ends in :<number> without a preceeding colon which implies ipv6

Definition at line 223 of file http_plugin.cpp.

223 {
224 if (!validate_host) {
225 return true;
226 }
227
228 // normalise the incoming host so that it always has the explicit port
229 static auto has_port_expr = regex("[^:]:[0-9]+$");
230 if (std::regex_search(host, has_port_expr)) {
231 return host_port_is_valid( host, endpoint_local_host_port );
232 } else {
233 // according to RFC 2732 ipv6 addresses should always be enclosed with brackets so we shouldn't need to special case here
234 return host_port_is_valid( host + ":" + std::to_string(secure ? websocketpp::uri_default_secure_port : websocketpp::uri_default_port ), endpoint_local_host_port);
235 }
236 }
bool host_port_is_valid(const std::string &header_host_port, const string &endpoint_local_host_port)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ host_port_is_valid()

bool sysio::http_plugin_impl::host_port_is_valid ( const std::string & header_host_port,
const string & endpoint_local_host_port )
inline

Definition at line 219 of file http_plugin.cpp.

219 {
220 return !validate_host || header_host_port == endpoint_local_host_port || valid_hosts.find(header_host_port) != valid_hosts.end();
221 }
Here is the caller graph for this function:

◆ make_abstract_conn_ptr()

template<typename T >
static detail::abstract_conn_ptr sysio::http_plugin_impl::make_abstract_conn_ptr ( detail::connection_ptr< T > conn,
http_plugin_impl_ptr impl )
inlinestatic

Helper to construct an abstract_conn_impl for a given connection and instance of http_plugin_impl

Template Parameters
T- The downstream parameter for the connection_ptr
Parameters
conn- existing connection_ptr<T>
impl- the owning http_plugin_impl
Returns
abstract_conn_ptr backed by type specific implementations of the methods

Definition at line 394 of file http_plugin.cpp.

394 {
395 return std::make_shared<abstract_conn_impl<T>>(std::move(conn), std::move(impl));
396 }

◆ make_app_thread_url_handler()

static detail::internal_url_handler sysio::http_plugin_impl::make_app_thread_url_handler ( int priority,
url_handler next,
http_plugin_impl_ptr my )
inlinestatic

Make an internal_url_handler that will run the url_handler on the app() thread and then return to the http thread pool for response processing

Precondition
b.size() has been added to bytes_in_flight by caller
Parameters
priority- priority to post to the app thread at
next- the next handler for responses
my- the http_plugin_impl
Returns
the constructed internal_url_handler

Definition at line 478 of file http_plugin.cpp.

478 {
479 auto next_ptr = std::make_shared<url_handler>(std::move(next));
480 return [my=std::move(my), priority, next_ptr=std::move(next_ptr)]
481 ( detail::abstract_conn_ptr conn, string r, string b, url_response_callback then ) {
482 auto tracked_b = make_in_flight<string>(std::move(b), my);
483 if (!conn->verify_max_bytes_in_flight()) {
484 return;
485 }
486
487 url_response_callback wrapped_then = [tracked_b, then=std::move(then)](int code, fc::variant resp) {
488 then(code, std::move(resp));
489 };
490
491 // post to the app thread taking shared ownership of next (via std::shared_ptr),
492 // sole ownership of the tracked body and the passed in parameters
493 app().post( priority, [next_ptr, conn=std::move(conn), r=std::move(r), tracked_b, wrapped_then=std::move(wrapped_then)]() mutable {
494 try {
495 // call the `next` url_handler and wrap the response handler
496 (*next_ptr)( std::move( r ), std::move(*(*tracked_b)), std::move(wrapped_then)) ;
497 } catch( ... ) {
498 conn->handle_exception();
499 }
500 } );
501 };
502 }
const mie::Vuint & r
Definition bn.cpp:28
auto post(int priority, Func &&func)
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object's.
Definition variant.hpp:191
static auto make_in_flight(T &&object, http_plugin_impl_ptr impl)
application & app()
std::function< void(int, fc::variant)> url_response_callback
A callback function provided to a URL handler to allow it to specify the HTTP response code and body.
Here is the call graph for this function:

◆ make_http_response_handler()

template<typename T >
auto sysio::http_plugin_impl::make_http_response_handler ( detail::abstract_conn_ptr abstract_conn_ptr)
inline

Construct a lambda appropriate for url_response_callback that will JSON-stringify the provided response

Parameters
con- pointer for the connection this response should be sent to
Returns
lambda suitable for url_response_callback

Definition at line 529 of file http_plugin.cpp.

529 {
530 return [my=shared_from_this(), abstract_conn_ptr]( int code, fc::variant response ) {
531 auto tracked_response = make_in_flight(std::move(response), my);
532 if (!abstract_conn_ptr->verify_max_bytes_in_flight()) {
533 return;
534 }
535
536 // post back to an HTTP thread to to allow the response handler to be called from any thread
537 boost::asio::post( my->thread_pool->get_executor(),
538 [my, abstract_conn_ptr, code, tracked_response=std::move(tracked_response)]() {
539 try {
540 std::string json = fc::json::to_string( *(*tracked_response), fc::time_point::now() + my->max_response_time );
541 auto tracked_json = make_in_flight(std::move(json), my);
542 abstract_conn_ptr->send_response(std::move(*(*tracked_json)), code);
543 } catch( ... ) {
544 abstract_conn_ptr->handle_exception();
545 }
546 });
547 };
548 }
Here is the call graph for this function:

◆ make_http_thread_url_handler()

static detail::internal_url_handler sysio::http_plugin_impl::make_http_thread_url_handler ( url_handler next)
inlinestatic

Make an internal_url_handler that will run the url_handler directly

Precondition
b.size() has been added to bytes_in_flight by caller
Parameters
next- the next handler for responses
Returns
the constructed internal_url_handler

Definition at line 511 of file http_plugin.cpp.

511 {
512 return [next=std::move(next)]( detail::abstract_conn_ptr conn, string r, string b, url_response_callback then ) {
513 try {
514 next(std::move(r), std::move(b), std::move(then));
515 } catch( ... ) {
516 conn->handle_exception();
517 }
518 };
519 }
uint32_t next(octet_iterator &it, octet_iterator end)
Definition checked.h:137

◆ make_in_flight()

template<typename T >
static auto sysio::http_plugin_impl::make_in_flight ( T && object,
http_plugin_impl_ptr impl )
inlinestatic

convenient wrapper to make an in_flight<T>

Definition at line 464 of file http_plugin.cpp.

464 {
465 return std::make_shared<in_flight<T>>(std::forward<T>(object), std::move(impl));
466 }
Here is the caller graph for this function:

◆ on_tls_init()

ssl_context_ptr sysio::http_plugin_impl::on_tls_init ( websocketpp::connection_hdl hdl)
inline

Definition at line 238 of file http_plugin.cpp.

238 {
239 ssl_context_ptr ctx = websocketpp::lib::make_shared<websocketpp::lib::asio::ssl::context>(asio::ssl::context::sslv23_server);
240
241 try {
242 ctx->set_options(asio::ssl::context::default_workarounds |
243 asio::ssl::context::no_sslv2 |
244 asio::ssl::context::no_sslv3 |
245 asio::ssl::context::no_tlsv1 |
246 asio::ssl::context::no_tlsv1_1 |
247 asio::ssl::context::single_dh_use);
248
249 ctx->use_certificate_chain_file(https_cert_chain);
250 ctx->use_private_key_file(https_key, asio::ssl::context::pem);
251
252 //going for the A+! Do a few more things on the native context to get ECDH in use
253
254 fc::ec_key ecdh = EC_KEY_new_by_curve_name(https_ecdh_curve == SECP384R1 ? NID_secp384r1 : NID_X9_62_prime256v1);
255 if (!ecdh)
256 SYS_THROW(chain::http_exception, "Failed to set NID_secp384r1");
257 if(SSL_CTX_set_tmp_ecdh(ctx->native_handle(), (EC_KEY*)ecdh) != 1)
258 SYS_THROW(chain::http_exception, "Failed to set ECDH PFS");
259
260 if(SSL_CTX_set_cipher_list(ctx->native_handle(), \
261 "EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:AES256:" \
262 "!DHE:!RSA:!AES128:!RC4:!DES:!3DES:!DSS:!SRP:!PSK:!EXP:!MD5:!LOW:!aNULL:!eNULL") != 1)
263 SYS_THROW(chain::http_exception, "Failed to set HTTPS cipher list");
264 } catch (const fc::exception& e) {
265 fc_elog( logger, "https server initialization error: ${w}", ("w", e.to_detail_string()) );
266 } catch(std::exception& e) {
267 fc_elog( logger, "https server initialization error: ${w}", ("w", e.what()) );
268 }
269
270 return ctx;
271 }
#define SYS_THROW(exc_type, FORMAT,...)
https_ecdh_curve_t https_ecdh_curve
websocketpp::lib::shared_ptr< websocketpp::lib::asio::ssl::context > ssl_context_ptr
Here is the call graph for this function:

◆ operator=() [1/2]

http_plugin_impl & sysio::http_plugin_impl::operator= ( const http_plugin_impl & )
delete

◆ operator=() [2/2]

http_plugin_impl & sysio::http_plugin_impl::operator= ( http_plugin_impl && )
delete

◆ verify_max_bytes_in_flight()

template<typename T >
bool sysio::http_plugin_impl::verify_max_bytes_in_flight ( const T & con)
inline

Definition at line 329 of file http_plugin.cpp.

329 {
330 auto bytes_in_flight_size = bytes_in_flight.load();
331 if( bytes_in_flight_size > max_bytes_in_flight ) {
332 fc_dlog( logger, "429 - too many bytes in flight: ${bytes}", ("bytes", bytes_in_flight_size) );
333 error_results::error_info ei;
335 ei.name = "Busy";
336 ei.what = "Too many bytes in flight: " + std::to_string( bytes_in_flight_size );
340 con->send_http_response();
341 return false;
342 }
343
344 return true;
345 }
static constexpr time_point maximum()
Definition time.hpp:46
std::atomic< size_t > bytes_in_flight
Here is the call graph for this function:

Member Data Documentation

◆ access_control_allow_credentials

bool sysio::http_plugin_impl::access_control_allow_credentials = false

Definition at line 195 of file http_plugin.cpp.

◆ access_control_allow_headers

string sysio::http_plugin_impl::access_control_allow_headers

Definition at line 193 of file http_plugin.cpp.

◆ access_control_allow_origin

string sysio::http_plugin_impl::access_control_allow_origin

Definition at line 192 of file http_plugin.cpp.

◆ access_control_max_age

string sysio::http_plugin_impl::access_control_max_age

Definition at line 194 of file http_plugin.cpp.

◆ bytes_in_flight

std::atomic<size_t> sysio::http_plugin_impl::bytes_in_flight {0}

Definition at line 202 of file http_plugin.cpp.

202{0};

◆ https_cert_chain

string sysio::http_plugin_impl::https_cert_chain

Definition at line 207 of file http_plugin.cpp.

◆ https_ecdh_curve

https_ecdh_curve_t sysio::http_plugin_impl::https_ecdh_curve = SECP384R1

Definition at line 209 of file http_plugin.cpp.

◆ https_key

string sysio::http_plugin_impl::https_key

Definition at line 208 of file http_plugin.cpp.

◆ https_listen_endpoint

std::optional<tcp::endpoint> sysio::http_plugin_impl::https_listen_endpoint

Definition at line 206 of file http_plugin.cpp.

◆ https_server

websocket_server_tls_type sysio::http_plugin_impl::https_server

Definition at line 211 of file http_plugin.cpp.

◆ listen_endpoint

std::optional<tcp::endpoint> sysio::http_plugin_impl::listen_endpoint

Definition at line 191 of file http_plugin.cpp.

◆ max_body_size

size_t sysio::http_plugin_impl::max_body_size {2*1024*1024}

Definition at line 196 of file http_plugin.cpp.

196{2*1024*1024};

◆ max_bytes_in_flight

size_t sysio::http_plugin_impl::max_bytes_in_flight = 0

Definition at line 203 of file http_plugin.cpp.

◆ max_response_time

fc::microseconds sysio::http_plugin_impl::max_response_time {30*1000}

Definition at line 204 of file http_plugin.cpp.

204{30*1000};

◆ server

websocket_server_type sysio::http_plugin_impl::server

Definition at line 198 of file http_plugin.cpp.

◆ thread_pool

std::optional<sysio::chain::named_thread_pool> sysio::http_plugin_impl::thread_pool

Definition at line 201 of file http_plugin.cpp.

◆ thread_pool_size

uint16_t sysio::http_plugin_impl::thread_pool_size = 2

Definition at line 200 of file http_plugin.cpp.

◆ unix_endpoint

std::optional<asio::local::stream_protocol::endpoint> sysio::http_plugin_impl::unix_endpoint

Definition at line 213 of file http_plugin.cpp.

◆ unix_server

websocket_local_server_type sysio::http_plugin_impl::unix_server

Definition at line 214 of file http_plugin.cpp.

◆ url_handlers

map<string,detail::internal_url_handler> sysio::http_plugin_impl::url_handlers

Definition at line 190 of file http_plugin.cpp.

◆ valid_hosts

set<string> sysio::http_plugin_impl::valid_hosts

Definition at line 217 of file http_plugin.cpp.

◆ validate_host

bool sysio::http_plugin_impl::validate_host = true

Definition at line 216 of file http_plugin.cpp.


The documentation for this class was generated from the following file: