Support the HTTP OPTIONS verb for RPC (#1667)
Useful for preflighting requests when using CORS.
This commit is contained in:
parent
65b25846c7
commit
82734f2218
4 changed files with 79 additions and 27 deletions
|
@ -1757,10 +1757,18 @@ TEST (rpc, version)
|
|||
ASSERT_EQ (boost::str (boost::format ("Nano %1%") % NANO_MAJOR_MINOR_RC_VERSION), response1.json.get<std::string> ("node_vendor"));
|
||||
}
|
||||
auto headers (response1.resp.base ());
|
||||
auto allowed_origin (headers.at ("Access-Control-Allow-Origin"));
|
||||
auto allowed_headers (headers.at ("Access-Control-Allow-Headers"));
|
||||
ASSERT_EQ ("*", allowed_origin);
|
||||
ASSERT_EQ ("Accept, Accept-Language, Content-Language, Content-Type", allowed_headers);
|
||||
auto allow (headers.at ("Allow"));
|
||||
auto content_type (headers.at ("Content-Type"));
|
||||
auto access_control_allow_origin (headers.at ("Access-Control-Allow-Origin"));
|
||||
auto access_control_allow_methods (headers.at ("Access-Control-Allow-Methods"));
|
||||
auto access_control_allow_headers (headers.at ("Access-Control-Allow-Headers"));
|
||||
auto connection (headers.at ("Connection"));
|
||||
ASSERT_EQ ("POST, OPTIONS", allow);
|
||||
ASSERT_EQ ("application/json", content_type);
|
||||
ASSERT_EQ ("*", access_control_allow_origin);
|
||||
ASSERT_EQ (allow, access_control_allow_methods);
|
||||
ASSERT_EQ ("Accept, Accept-Language, Content-Language, Content-Type", access_control_allow_headers);
|
||||
ASSERT_EQ ("close", connection);
|
||||
}
|
||||
|
||||
TEST (rpc, work_generate)
|
||||
|
|
|
@ -4038,17 +4038,24 @@ void nano::rpc_connection::parse_connection ()
|
|||
read ();
|
||||
}
|
||||
|
||||
void nano::rpc_connection::write_result (std::string body, unsigned version)
|
||||
void nano::rpc_connection::prepare_head (unsigned version, boost::beast::http::status status)
|
||||
{
|
||||
res.version (version);
|
||||
res.result (status);
|
||||
res.set (boost::beast::http::field::allow, "POST, OPTIONS");
|
||||
res.set (boost::beast::http::field::content_type, "application/json");
|
||||
res.set (boost::beast::http::field::access_control_allow_origin, "*");
|
||||
res.set (boost::beast::http::field::access_control_allow_methods, "POST, OPTIONS");
|
||||
res.set (boost::beast::http::field::access_control_allow_headers, "Accept, Accept-Language, Content-Language, Content-Type");
|
||||
res.set (boost::beast::http::field::connection, "close");
|
||||
}
|
||||
|
||||
void nano::rpc_connection::write_result (std::string body, unsigned version, boost::beast::http::status status)
|
||||
{
|
||||
if (!responded.test_and_set ())
|
||||
{
|
||||
res.set ("Content-Type", "application/json");
|
||||
res.set ("Access-Control-Allow-Origin", "*");
|
||||
res.set ("Access-Control-Allow-Headers", "Accept, Accept-Language, Content-Language, Content-Type");
|
||||
res.set ("Connection", "close");
|
||||
res.result (boost::beast::http::status::ok);
|
||||
prepare_head (version, status);
|
||||
res.body () = body;
|
||||
res.version (version);
|
||||
res.prepare_payload ();
|
||||
}
|
||||
else
|
||||
|
@ -4082,14 +4089,28 @@ void nano::rpc_connection::read ()
|
|||
BOOST_LOG (this_l->node->log) << boost::str (boost::format ("RPC request %2% completed in: %1% microseconds") % std::chrono::duration_cast<std::chrono::microseconds> (std::chrono::steady_clock::now () - start).count () % request_id);
|
||||
}
|
||||
});
|
||||
if (this_l->request.method () == boost::beast::http::verb::post)
|
||||
auto method = this_l->request.method ();
|
||||
switch (method)
|
||||
{
|
||||
auto handler (std::make_shared<nano::rpc_handler> (*this_l->node, this_l->rpc, this_l->request.body (), request_id, response_handler));
|
||||
handler->process_request ();
|
||||
}
|
||||
else
|
||||
{
|
||||
error_response (response_handler, "Can only POST requests");
|
||||
case boost::beast::http::verb::post:
|
||||
{
|
||||
auto handler (std::make_shared<nano::rpc_handler> (*this_l->node, this_l->rpc, this_l->request.body (), request_id, response_handler));
|
||||
handler->process_request ();
|
||||
break;
|
||||
}
|
||||
case boost::beast::http::verb::options:
|
||||
{
|
||||
this_l->prepare_head (version);
|
||||
this_l->res.prepare_payload ();
|
||||
boost::beast::http::async_write (this_l->socket, this_l->res, [this_l](boost::system::error_code const & ec, size_t bytes_transferred) {
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
error_response (response_handler, "Can only POST requests");
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -96,7 +96,8 @@ public:
|
|||
virtual ~rpc_connection () = default;
|
||||
virtual void parse_connection ();
|
||||
virtual void read ();
|
||||
virtual void write_result (std::string body, unsigned version);
|
||||
virtual void prepare_head (unsigned version, boost::beast::http::status status = boost::beast::http::status::ok);
|
||||
virtual void write_result (std::string body, unsigned version, boost::beast::http::status status = boost::beast::http::status::ok);
|
||||
std::shared_ptr<nano::node> node;
|
||||
nano::rpc & rpc;
|
||||
boost::asio::ip::tcp::socket socket;
|
||||
|
|
|
@ -176,15 +176,37 @@ void nano::rpc_connection_secure::read ()
|
|||
BOOST_LOG (this_l->node->log) << boost::str (boost::format ("TLS: RPC request %2% completed in: %1% microseconds") % std::chrono::duration_cast<std::chrono::microseconds> (std::chrono::steady_clock::now () - start).count () % request_id);
|
||||
}
|
||||
});
|
||||
auto method = this_l->request.method ();
|
||||
switch (method)
|
||||
{
|
||||
case boost::beast::http::verb::post:
|
||||
{
|
||||
auto handler (std::make_shared<rai::rpc_handler> (*this_l->node, this_l->rpc, this_l->request.body (), request_id, response_handler));
|
||||
handler->process_request ();
|
||||
break;
|
||||
}
|
||||
case boost::beast::http::verb::options:
|
||||
{
|
||||
this_l->prepare_head (version);
|
||||
this_l->res.set (boost::beast::http::field::allow, "POST, OPTIONS");
|
||||
this_l->res.prepare_payload ();
|
||||
boost::beast::http::async_write (this_l->stream, this_l->res, [this_l](boost::system::error_code const & ec, size_t bytes_transferred) {
|
||||
|
||||
if (this_l->request.method () == boost::beast::http::verb::post)
|
||||
{
|
||||
auto handler (std::make_shared<nano::rpc_handler> (*this_l->node, this_l->rpc, this_l->request.body (), request_id, response_handler));
|
||||
handler->process_request ();
|
||||
}
|
||||
else
|
||||
{
|
||||
error_response (response_handler, "Can only POST requests");
|
||||
// Perform the SSL shutdown
|
||||
this_l->stream.async_shutdown (
|
||||
std::bind (
|
||||
&rai::rpc_connection_secure::on_shutdown,
|
||||
this_l,
|
||||
std::placeholders::_1));
|
||||
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
error_response (response_handler, "Can only POST requests");
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue