this is what my fileCollector looks like, it just stores a "cache" of files (so that you don't read the file during each request)
class FileCollector
{
public:
FileCollector();
std::string get_file_data(std::string s);
private:
std::map<std::string, std::string> fileData;
};
The error is most likely here, but due to inexperience I can't find it.
http_connection::http_connection(tcp::socket socket, std::shared_ptr<Collector::FileCollector> fc)
: socket_(std::move(socket)),
filecollector(fc)
{}
void http_connection::start(void)
{
read_request();
}
void http_connection::read_request(void)
{
auto self = shared_from_this();
http::async_read(
socket_,
buffer_,
request_,
[self](beast::error_code ec,
std::size_t bytes_transferred)
{
boost::ignore_unused(bytes_transferred);
if(!ec)
self->process_request();
}
);
}
void http_connection::process_request(void)
{
response_.version(request_.version());
response_.keep_alive(false);
switch (request_.method())
{
case (http::verb::get):
response_.result(http::status::ok);
response_.set(http::field::server, "Beast");
create_response();
break;
default:
response_.result(http::status::bad_request);
response_.set(http::field::content_type, "text/plain");
beast::ostream(response_.body())
<< "Invalid request-method '"
<< std::string(request_.method_string())
<< "'";
break;
}
write_response();
}
void http_connection::create_response(void)
{
std::string_view sv = request_.target().substr(1);
std::string targetfile = {sv.data(), sv.size()};
beast::ostream(response_.body())
<< filecollector->get_file_data(targetfile);
}
void http_connection::write_response(void)
{
auto self = shared_from_this();
response_.content_length(response_.body().size());
http::async_write(
socket_,
response_,
[self](beast::error_code er, std::size_t bytes_trans)
{
self->socket_.shutdown(tcp::socket::shutdown_send, er);
}
);
}
the way I start connections
void ownHTTPServer::start_acceptor(tcp::acceptor& accepter, tcp::socket& sock,
std::shared_ptr<Collector::FileCollector> &fc)
{
accepter.async_accept(sock,
[&](beast::error_code er){
if (!er)
{
std::make_shared<ownHTTPServer::http_connection>
(std::move(sock), std::move(fc))->start();
}
start_acceptor(accepter, sock, fc);
});
}
g++ -IC:\boost\include\boost-1_84 -lws2_32 -lwsock32 ... compliler x86_64-w64-mingw32
the code works if you don't use filecollector and the response content is const char*
If it's not difficult for someone, I would like to read articles on how boost.asio works
In start_acceptor()
, each time a new client is accepted, you are creating a new http_connection
object and moving (not sharing) ownership of your shared_ptr<FileCollector> fc
object into that connection:
std::make_shared<ownHTTPServer::http_connection>
(std::move(sock), std::move(fc))->start();
^^^^^^^^^^^^^
Thus, fc
loses access to the FileCollector
object in memory, making it unavailable when subsequent connections transfer fc
again and again.
You should not be using std::move()
to transfer ownership of a std::shared_ptr
, that defeats the whole point of using shared ownership.
Your http_connection
constructor takes the shared_ptr
by value, as it should. So, simply do not use std::move()
when passing fc
to that constructor, let fc
be copied so the FileCollector
object is properly shared across multiple shared_ptr
instances:
std::make_shared<ownHTTPServer::http_connection>
(std::move(sock), fc)->start();
^^
Along those same lines, you should also be capturing fc
by value, not by reference (just as you do with self
in http_connection::read_request()
), eg:
accepter.async_accept(sock,
[&,fc](beast::error_code er){
^^
if (!er)
{
std::make_shared<ownHTTPServer::http_connection>
(std::move(sock), fc)->start();
}
start_acceptor(accepter, sock, fc);
});
That way, the FileCollector
object is shared properly while the async_accept()
handler is waiting to be called.