TrinityCore
Loading...
Searching...
No Matches
BaseHttpSocket.h
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef TRINITYCORE_BASE_HTTP_SOCKET_H
19#define TRINITYCORE_BASE_HTTP_SOCKET_H
20
21#include "HttpCommon.h"
22#include "HttpSessionState.h"
23#include "Optional.h"
24#include "Socket.h"
26#include <boost/beast/core/basic_stream.hpp>
27#include <boost/beast/http/parser.hpp>
28#include <boost/beast/http/string_body.hpp>
29
30namespace Trinity::Net::Http
31{
32using IoContextHttpSocket = boost::beast::basic_stream<boost::asio::ip::tcp, boost::asio::io_context::executor_type, boost::beast::unlimited_rate_policy>;
33
34namespace Impl
35{
37{
38public:
39 using IoContextHttpSocket::basic_stream;
40
41 bool is_open() const
42 {
43 return socket().is_open();
44 }
45
46 void close(boost::system::error_code& /*error*/)
47 {
48 IoContextHttpSocket::close();
49 }
50
51 void shutdown(boost::asio::socket_base::shutdown_type what, boost::system::error_code& shutdownError)
52 {
53 socket().shutdown(what, shutdownError);
54 }
55
56 template<typename WaitHandlerType>
57 void async_wait(boost::asio::socket_base::wait_type type, WaitHandlerType&& handler)
58 {
59 socket().async_wait(type, std::forward<WaitHandlerType>(handler));
60 }
61
62 template <typename SettableSocketOption>
63 void set_option(SettableSocketOption const& option, boost::system::error_code& ec)
64 {
65 socket().set_option(option, ec);
66 }
67
68 IoContextTcpSocket::endpoint_type remote_endpoint() const
69 {
70 return socket().remote_endpoint();
71 }
72};
73}
74
75using RequestParser = boost::beast::http::request_parser<RequestBody>;
76using ResponseParser = boost::beast::http::response_parser<RequestBody>;
77
79{
80public:
81 AbstractSocket() = default;
82 AbstractSocket(AbstractSocket const& other) = default;
83 AbstractSocket(AbstractSocket&& other) = default;
84 AbstractSocket& operator=(AbstractSocket const& other) = default;
86 virtual ~AbstractSocket() = default;
87
88 static bool ParseRequest(MessageBuffer& packet, RequestParser& parser);
89 static bool ParseResponse(MessageBuffer& packet, ResponseParser& parser);
90
91 static MessageBuffer SerializeRequest(Request const& request);
92 static MessageBuffer SerializeResponse(Request const& request, Response const& response);
93
94 virtual void SendResponse(RequestContext& context) = 0;
95
96 void LogRequestAndResponse(RequestContext const& context, MessageBuffer& buffer) const;
97
98 virtual std::string GetClientInfo() const = 0;
99
100 static std::string GetClientInfo(boost::asio::ip::address const& address, uint16 port, SessionState const* state);
101
102 virtual SessionState* GetSessionState() const = 0;
103
105 {
106 if (SessionState* state = this->GetSessionState())
107 return state->Id;
108
109 return {};
110 }
111
112 virtual void Start() = 0;
113
114 virtual bool Update() = 0;
115
116 virtual boost::asio::ip::address const& GetRemoteIpAddress() const = 0;
117
118 virtual bool IsOpen() const = 0;
119
120 virtual void CloseSocket() = 0;
121};
122
123template <typename SocketImpl>
125{
126 explicit HttpConnectionInitializer(SocketImpl* socket) : _socket(socket) { }
127
128 void Start() override
129 {
130 _socket->ResetHttpParser();
131
132 this->InvokeNext();
133 }
134
135private:
136 SocketImpl* _socket;
137};
138
139template<typename Stream>
140class BaseSocket : public Trinity::Net::Socket<Stream>, public AbstractSocket
141{
143
144public:
145 using Base::Base;
146
147 BaseSocket(BaseSocket const& other) = delete;
148 BaseSocket(BaseSocket&& other) = delete;
149 BaseSocket& operator=(BaseSocket const& other) = delete;
150 BaseSocket& operator=(BaseSocket&& other) = delete;
151
152 ~BaseSocket() = default;
153
155 {
156 MessageBuffer& packet = this->GetReadBuffer();
157 while (packet.GetActiveSize() > 0)
158 {
159 if (!ParseRequest(packet, *_httpParser))
160 {
161 // Couldn't receive the whole data this time.
162 break;
163 }
164
165 if (!HandleMessage(_httpParser->get()))
166 {
167 this->CloseSocket();
169 }
170
171 this->ResetHttpParser();
172 }
173
175 }
176
177 bool HandleMessage(Request& request)
178 {
179 RequestContext context { .request = std::move(request) };
180
181 if (!_state)
182 _state = this->ObtainSessionState(context);
183
184 RequestHandlerResult status = this->RequestHandler(context);
185
186 if (status != RequestHandlerResult::Async)
187 this->SendResponse(context);
188
189 return status != RequestHandlerResult::Error;
190 }
191
193
194 void SendResponse(RequestContext& context) final
195 {
196 context.response.prepare_payload();
197
198 MessageBuffer buffer = SerializeResponse(context.request, context.response);
199
200 this->LogRequestAndResponse(context, buffer);
201
202 this->QueuePacket(std::move(buffer));
203
204 if (!context.response.keep_alive())
205 this->DelayedCloseSocket();
206 }
207
208 void Start() override { return this->Base::Start(); }
209
210 bool Update() override { return this->Base::Update(); }
211
212 boost::asio::ip::address const& GetRemoteIpAddress() const final { return this->Base::GetRemoteIpAddress(); }
213
214 bool IsOpen() const final { return this->Base::IsOpen(); }
215
216 void CloseSocket() final { return this->Base::CloseSocket(); }
217
218 std::string GetClientInfo() const override
219 {
220 return AbstractSocket::GetClientInfo(this->GetRemoteIpAddress(), this->GetRemotePort(), this->_state.get());
221 }
222
223 SessionState* GetSessionState() const override { return _state.get(); }
224
226 {
227 this->_httpParser.reset();
228 this->_httpParser.emplace();
229 this->_httpParser->eager(true);
230 }
231
232protected:
233 virtual std::shared_ptr<SessionState> ObtainSessionState(RequestContext& context) const = 0;
234
236 std::shared_ptr<SessionState> _state;
237};
238}
239
240#endif // TRINITYCORE_BASE_HTTP_SOCKET_H
#define TC_NETWORK_API
Definition Define.h:117
uint16_t uint16
Definition Define.h:155
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
size_type GetActiveSize() const
AbstractSocket(AbstractSocket &&other)=default
virtual std::string GetClientInfo() const =0
virtual void SendResponse(RequestContext &context)=0
Optional< boost::uuids::uuid > GetSessionId() const
virtual bool IsOpen() const =0
AbstractSocket & operator=(AbstractSocket &&other)=default
AbstractSocket(AbstractSocket const &other)=default
static bool ParseRequest(MessageBuffer &packet, RequestParser &parser)
virtual SessionState * GetSessionState() const =0
void LogRequestAndResponse(RequestContext const &context, MessageBuffer &buffer) const
static MessageBuffer SerializeResponse(Request const &request, Response const &response)
AbstractSocket & operator=(AbstractSocket const &other)=default
virtual boost::asio::ip::address const & GetRemoteIpAddress() const =0
Optional< RequestParser > _httpParser
virtual std::shared_ptr< SessionState > ObtainSessionState(RequestContext &context) const =0
BaseSocket & operator=(BaseSocket const &other)=delete
BaseSocket(BaseSocket const &other)=delete
std::string GetClientInfo() const override
virtual RequestHandlerResult RequestHandler(RequestContext &context)=0
SocketReadCallbackResult ReadHandler() final
SessionState * GetSessionState() const override
BaseSocket(BaseSocket &&other)=delete
void SendResponse(RequestContext &context) final
boost::asio::ip::address const & GetRemoteIpAddress() const final
BaseSocket & operator=(BaseSocket &&other)=delete
bool HandleMessage(Request &request)
std::shared_ptr< SessionState > _state
void shutdown(boost::asio::socket_base::shutdown_type what, boost::system::error_code &shutdownError)
IoContextTcpSocket::endpoint_type remote_endpoint() const
void async_wait(boost::asio::socket_base::wait_type type, WaitHandlerType &&handler)
void set_option(SettableSocketOption const &option, boost::system::error_code &ec)
void close(boost::system::error_code &)
uint16 GetRemotePort() const
Definition Socket.h:191
boost::asio::ip::address const & GetRemoteIpAddress() const
Definition Socket.h:186
void QueuePacket(MessageBuffer &&buffer)
Definition Socket.h:216
void DelayedCloseSocket()
Marks the socket for closing after write buffer becomes empty.
Definition Socket.h:242
MessageBuffer & GetReadBuffer()
Definition Socket.h:252
boost::beast::http::response< ResponseBody > Response
Definition HttpCommon.h:31
boost::beast::http::request_parser< RequestBody > RequestParser
boost::beast::http::response_parser< RequestBody > ResponseParser
boost::beast::basic_stream< boost::asio::ip::tcp, boost::asio::io_context::executor_type, boost::beast::unlimited_rate_policy > IoContextHttpSocket
boost::beast::http::request< RequestBody > Request
Definition HttpCommon.h:30
SocketReadCallbackResult
Definition Socket.h:49