I have a websocket server(listening the loopback interface) that should respond to a GET request. Here's how I do that
ws_.async_accept_ex(
[self = shared_from_this()](websocket::response_type& res) //
{
if (res.result_int() == 400) { // bad request, assume HTTP GET
osstream response;
/* invoke request handlers */
for (auto& do_handle : self->handlers) {
do_handle({ "GET" }, response);
/* if responded, assing response to the body*/
if (response.tellp()) {
res.content_length(response.str().size());
res.body() = std::move(response.str());
break;
}
}
}
},
net::bind_executor(strand_,
[self = shared_from_this()](beast::error_code ec) {
self->on_accept(ec);
}));
But I also need to be able to handle locations(like localhost:2019/some_location
).
Is there a way?
Solution: read the header manually, check if it's an upgrade
beast::flat_buffer buffer_;
websocket::request_type req_;
/*
...
...
*/
http::async_read(ws_.next_layer(), buffer_, req_,
[self=shared_from_this()](beast::error_code ec, size_t)
{
if(ec){
fail(ec, "[http] read");
return;
}
if(websocket::is_upgrade(self->req_)){
self->ws_.accept(self->req_,ec);
self->on_accept(ec);
}
else{
osstream response;
websocket::response_type res;
vector<string_view> req_args
{ "GET", self->req_.base().target().begin() };
/* invoke request handlers */
for(auto &do_handle : self->handlers){
do_handle(req_args, response);
/* if responded, assing response to the body*/
if(response.tellp()){
res.content_length(response.str().size());
res.body() = std::move(response.str());
break;
}}
http::write(self->ws_.next_layer(), res);
}
});
The request-target for a WebSocket Upgrade request must be in origin-form. "localhost:2019/some_location" is in absolute-form and therefore illegal. It sounds to me like what you want is to be able to specially handle HTTP requests which are not WebSocket upgrades, and for the actual WebSocket upgrades let the websocket stream handle it by performing the handshake.
This is covered in the documentation: https://www.boost.org/doc/libs/1_69_0/libs/beast/doc/html/beast/using_websocket/handshaking_servers.html#beast.using_websocket.handshaking_servers.passing_http_requests
And also in the examples: https://github.com/boostorg/beast/blob/06efddd8b851610b5b3a5832ac87f1c52b838d9b/example/advanced/server/advanced_server.cpp#L665
tl;dr: Read the request yourself using beast::http::async_read
, see if it is a websocket upgrade using beast::websocket::is_upgrade
. If it is an upgrade, construct the beast::websocket::stream
and call async_accept
on it with the request, otherwise process the HTTP request the way you want and send back the response yourself using beast::http::async_write
.