217 lines
5.8 KiB
Plaintext
217 lines
5.8 KiB
Plaintext
#pragma once
|
|
|
|
|
|
// avoid breaking changes from 1.64 to.71
|
|
// Note that raspbian only prvides 1.64; ubuntu studio only provides 1.71
|
|
#define BOOST_BEAST_ALLOW_DEPRECATED
|
|
|
|
#include <boost/asio/ip/tcp.hpp>
|
|
#include <boost/beast/http.hpp>
|
|
#include <boost/asio/ip/network_v4.hpp>
|
|
|
|
|
|
#include <mutex>
|
|
#include <thread>
|
|
#include "Uri.hpp"
|
|
#include <string_view>
|
|
#include <filesystem>
|
|
|
|
|
|
// forward declaration.
|
|
|
|
class websocket_session;
|
|
|
|
namespace pipedal {
|
|
using HttpRequest =boost::beast::http::request<boost::beast::http::string_body>;
|
|
|
|
|
|
std::string last_modified(const std::filesystem::path& path);
|
|
|
|
class SocketHandler {
|
|
public:
|
|
|
|
class IWriteCallback {
|
|
public:
|
|
virtual void close() = 0;
|
|
|
|
virtual void writeCallback(const std::string& text) = 0;
|
|
virtual std::string getFromAddress() const = 0;
|
|
};
|
|
|
|
private:
|
|
friend class ::websocket_session;
|
|
|
|
|
|
IWriteCallback *writeCallback_;
|
|
|
|
void setWriteCallback(IWriteCallback *writeCallback) {
|
|
writeCallback_ = writeCallback;
|
|
}
|
|
|
|
protected:
|
|
virtual void onReceive(const std::string_view&text) = 0;
|
|
public:
|
|
std::string getFromAddress() const { return writeCallback_->getFromAddress(); }
|
|
void receive(const std::string_view&text) {
|
|
onReceive(text);
|
|
}
|
|
void send(const std::string &text) {
|
|
if (writeCallback_ != nullptr)
|
|
{
|
|
writeCallback_->writeCallback(text);
|
|
}
|
|
}
|
|
virtual void Close()
|
|
{
|
|
writeCallback_->close();
|
|
}
|
|
|
|
virtual ~SocketHandler() = default;
|
|
|
|
virtual void onAttach() { }
|
|
|
|
};
|
|
|
|
class ISocketFactory {
|
|
public:
|
|
virtual bool wants(const uri &request) = 0;
|
|
virtual std::shared_ptr<SocketHandler> CreateHandler(const uri& request) = 0;
|
|
};
|
|
|
|
class RequestHandler {
|
|
private:
|
|
uri target_url_;
|
|
public:
|
|
RequestHandler(const char*target_url)
|
|
: target_url_(target_url)
|
|
{
|
|
|
|
}
|
|
~RequestHandler() = default;
|
|
|
|
virtual bool wantsRedirect(const uri& requestUri)
|
|
{
|
|
return false;
|
|
}
|
|
uri GetRedirect(const uri& requestUri)
|
|
{
|
|
return requestUri;
|
|
}
|
|
|
|
virtual bool wants(boost::beast::http::verb verb,const uri &request_uri) const {
|
|
if (request_uri.segment_count() < target_url_.segment_count())
|
|
{
|
|
return false;
|
|
}
|
|
for (int i = 0; i < target_url_.segment_count(); ++i)
|
|
{
|
|
if (request_uri.segment(i) != target_url_.segment(i))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
virtual void head_response(
|
|
const uri&request_uri,
|
|
const boost::beast::http::request<boost::beast::http::string_body> &req,
|
|
boost::beast::http::response<boost::beast::http::empty_body> &res,
|
|
boost::beast::error_code &ec) = 0;
|
|
|
|
virtual void get_response(
|
|
const uri&request_uri,
|
|
const boost::beast::http::request<boost::beast::http::string_body> &req,
|
|
boost::beast::http::response<boost::beast::http::string_body> &res,
|
|
boost::beast::error_code &ec) = 0;
|
|
|
|
virtual void post_response(
|
|
const uri&request_uri,
|
|
const boost::beast::http::request<boost::beast::http::string_body> &req,
|
|
boost::beast::http::response<boost::beast::http::string_body> &res,
|
|
boost::beast::error_code &ec)
|
|
{
|
|
get_response(request_uri,req,res,ec);
|
|
}
|
|
|
|
|
|
};
|
|
class BeastServer {
|
|
private:
|
|
boost::asio::ip::address address;
|
|
unsigned short port;
|
|
std::string doc_root;
|
|
int threads;
|
|
std::mutex log_mutex;
|
|
std::vector<std::shared_ptr<RequestHandler> > request_handlers;
|
|
std::vector<std::shared_ptr<ISocketFactory> > socket_factories;
|
|
std::mutex io_mutex;
|
|
boost::asio::io_context *pIoContext = nullptr;
|
|
void*pListener = nullptr;
|
|
std::thread*pBgThread = nullptr;
|
|
|
|
bool logHttpRequests = false;
|
|
|
|
bool hasAccessPointGateway = false;
|
|
boost::asio::ip::network_v4 accessPointGateway;
|
|
std::string accessPointServerAddress;
|
|
bool stopping = false;
|
|
|
|
|
|
public:
|
|
|
|
BeastServer(
|
|
const boost::asio::ip::address& address,
|
|
int port,
|
|
const char*rootPath,
|
|
int threads = 10);
|
|
|
|
void Run();
|
|
void RunInBackground();
|
|
bool Stopping() const { return this->stopping; }
|
|
void Stop();
|
|
void Join();
|
|
|
|
void SetLogHttpRequests(bool logRequests) { this->logHttpRequests = logRequests; }
|
|
bool LogHttpRequests() const { return this->logHttpRequests; }
|
|
boost::asio::io_context& IoContext() {
|
|
return *pIoContext;
|
|
}
|
|
|
|
void AddRequestHandler(std::shared_ptr<RequestHandler> requestHandler)
|
|
{
|
|
request_handlers.push_back(requestHandler);
|
|
}
|
|
|
|
void AddSocketFactory(const std::shared_ptr<ISocketFactory> &socketHandler)
|
|
{
|
|
socket_factories.push_back(socketHandler);
|
|
}
|
|
|
|
std::vector<std::shared_ptr<RequestHandler> > &RequestHandlers() { return request_handlers; }
|
|
|
|
const std::string&GetDocRoot() { return doc_root; }
|
|
|
|
virtual ~BeastServer();
|
|
|
|
std::shared_ptr<ISocketFactory> GetSocketFactory(const uri &request_uri);
|
|
|
|
void SetAccessPointGateway(const boost::asio::ip::network_v4 &gateway, const std::string&accessPointServerAddress)
|
|
{
|
|
this->accessPointGateway = gateway;
|
|
this->hasAccessPointGateway = true;
|
|
this->accessPointServerAddress = accessPointServerAddress;
|
|
}
|
|
bool HasAccessPointGateway() const { return hasAccessPointGateway; }
|
|
boost::asio::ip::network_v4 &GetAccessPointGateway() { return this->accessPointGateway; }
|
|
const std::string & GetAccessPointServerAddress() const { return this->accessPointServerAddress; }
|
|
|
|
public:
|
|
virtual void onError(boost::system::error_code ec, char const* what);
|
|
virtual void onWarning(boost::system::error_code ec, char const* what);
|
|
virtual void onInfo(char const* what);
|
|
|
|
virtual void onListenerClosed();
|
|
};
|
|
|
|
} // namespace pipedal; |