update.
Some checks failed
Deploy / Build (push) Failing after 1m22s

This commit is contained in:
luocai
2025-05-14 17:14:33 +08:00
parent 836c8e0c44
commit 71485e7975
24 changed files with 122 additions and 95 deletions

View File

@ -1,5 +1,6 @@
add_library(Base
DataStructure.h DataStructure.cpp
HttpSession.h HttpSession.cpp
)
get_filename_component(PARENT_DIR ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
@ -9,4 +10,6 @@ target_include_directories(Base
target_link_libraries(Base
PRIVATE OpenSSL::Crypto
PUBLIC Kylin::Router
PUBLIC Kylin::Core
)

119
Base/HttpSession.cpp Normal file
View File

@ -0,0 +1,119 @@
#include "HttpSession.h"
#include "Core/Logger.h"
#include <boost/beast/http/read.hpp>
#include <boost/beast/version.hpp>
#include <boost/config.hpp>
#include <boost/stacktrace.hpp>
#include <boost/url/parse_path.hpp>
#include <boost/url/url_view.hpp>
#include <iostream>
#include <limits>
namespace Older {
HttpSession::HttpSession(boost::asio::ip::tcp::socket &&socket,
const std::shared_ptr<boost::urls::router<RequestHandler>> &router)
: m_stream(std::move(socket)), m_router(router) {
}
void HttpSession::run() {
doRead();
}
boost::beast::tcp_stream::executor_type HttpSession::executor() {
return m_stream.get_executor();
}
boost::asio::ip::tcp::socket HttpSession::releaseSocket() {
return m_stream.release_socket();
}
void HttpSession::errorReply(const Request &request, boost::beast::http::status status, boost::beast::string_view message) {
using namespace boost::beast;
// invalid route
http::response<http::string_body> res{status, request.version()};
res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
res.set(http::field::content_type, "text/html");
res.keep_alive(request.keep_alive());
res.body() = message;
res.prepare_payload();
reply(std::move(res));
}
void HttpSession::doRead() {
// Construct a new parser for each message
m_parser.emplace();
// Apply a reasonable limit to the allowed size
// of the body in bytes to prevent abuse.
m_parser->body_limit(std::numeric_limits<std::uint64_t>::max());
m_parser->header_limit(std::numeric_limits<std::uint32_t>::max());
m_buffer.clear();
// Set the timeout.
m_stream.expires_after(std::chrono::seconds(30));
// clang-format off
boost::beast::http::async_read(m_stream, m_buffer, *m_parser, [self{shared_from_this()}](const boost::system::error_code &ec, std::size_t bytes_transferred) {
self->onRead(ec, bytes_transferred);
});
// clang-format on
}
void HttpSession::onRead(const boost::beast::error_code &error, std::size_t) {
using namespace boost::beast;
if (error) {
if (error == http::error::end_of_stream) {
boost::beast::error_code e;
m_stream.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_send, e);
} else if (error != boost::asio::error::operation_aborted) {
LOG(info) << error << " : " << error.message();
}
return;
} else if (m_router.expired()) {
LOG(error) << "router is null.";
return;
}
auto &request = m_parser->get();
auto path = boost::urls::parse_path(request.target());
if (!path) {
LOG(error) << request.target() << "failed, error: " << path.error().message();
errorReply(request, http::status::bad_request, "Illegal request-target");
return;
}
auto router = m_router.lock();
boost::urls::matches matches;
auto handler = router->find(*path, matches);
if (handler) {
try {
(*handler)(*this, request, matches);
} catch (const std::exception &e) {
boost::stacktrace::stacktrace trace = boost::stacktrace::stacktrace::from_current_exception();
LOG(error) << e.what() << ", trace:\n" << trace;
}
} else {
std::ostringstream oss;
oss << "The resource '" << request.target() << "' was not found.";
auto message = oss.str();
errorReply(request, http::status::not_found, message);
LOG(error) << message;
}
}
void HttpSession::onWrite(boost::beast::error_code ec, std::size_t, bool close) {
if (ec) {
if (ec == boost::asio::error::operation_aborted) return;
std::cerr << "write: " << ec.message() << "\n";
}
if (close) {
// This means we should close the connection, usually because
// the response indicated the "Connection: close" semantic.
m_stream.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec);
return;
}
// Read another request
doRead();
}
} // namespace Older

51
Base/HttpSession.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef HTTPSESSION_H
#define HTTPSESSION_H
#include "Router/router.hpp"
#include <boost/beast/core/flat_buffer.hpp>
#include <boost/beast/core/tcp_stream.hpp>
#include <boost/beast/http/parser.hpp>
#include <boost/beast/http/string_body.hpp>
#include <boost/beast/http/write.hpp>
#include <cstdlib>
#include <memory>
#include <optional>
namespace Older {
/** Represents an established HTTP connection
*/
class HttpSession : public std::enable_shared_from_this<HttpSession> {
void doRead();
void onWrite(boost::beast::error_code ec, std::size_t, bool close);
public:
using Request = boost::beast::http::request<boost::beast::http::string_body>;
using RequestHandler = std::function<void(HttpSession &, const Request &, const boost::urls::matches &)>;
HttpSession(boost::asio::ip::tcp::socket &&socket, const std::shared_ptr<boost::urls::router<RequestHandler>> &router);
template <typename Response>
void reply(Response &&response) {
using ResponseType = typename std::decay_t<decltype(response)>;
auto sp = std::make_shared<ResponseType>(std::forward<decltype(response)>(response));
boost::beast::http::async_write(m_stream, *sp,
[self = shared_from_this(), sp](boost::beast::error_code ec, std::size_t bytes) {
self->onWrite(ec, bytes, sp->need_eof());
});
}
void errorReply(const Request &request, boost::beast::http::status status, boost::beast::string_view message);
boost::beast::tcp_stream::executor_type executor();
boost::asio::ip::tcp::socket releaseSocket();
void run();
protected:
void onRead(const boost::beast::error_code &error, std::size_t);
private:
boost::beast::tcp_stream m_stream;
std::weak_ptr<boost::urls::router<RequestHandler>> m_router;
boost::beast::flat_buffer m_buffer{std::numeric_limits<std::uint32_t>::max()};
std::optional<boost::beast::http::request_parser<boost::beast::http::string_body>> m_parser;
};
} // namespace Older
#endif // HTTPSESSION_H

View File

@ -2,10 +2,22 @@
#define __MESSAGES_H__
#include "Core/MessageManager.h"
#include "Router/matches.hpp"
#include <boost/beast/http/string_body.hpp>
#include <boost/callable_traits/return_type.hpp>
namespace Older {
struct NotifyServerChan {
using Signature = void(const boost::beast::http::request<boost::beast::http::string_body> &);
};
class HttpSession;
using HttpRequest = boost::beast::http::request<boost::beast::http::string_body>;
using RequestHandler = std::function<void(HttpSession &, const HttpRequest &, const boost::urls::matches &)>;
struct RegisterUrlHandler {
using Signature = void(std::string_view url, RequestHandler &&handler);
};
} // namespace Older
#endif // __MESSAGES_H__