38 std::string_view Method()
const;
39 const TUri& Uri()
const;
40 std::string_view Version()
const {
return Version_; }
45 bool BodyConsumed()
const;
46 bool RequireConnectionClose()
const;
47 const std::map<std::string_view, std::string_view>& Headers()
const;
50 void ParseRequestLine();
57 size_t HeaderStartPos_ = 0;
58 std::map<std::string_view, std::string_view> Headers_;
59 size_t ContentLength_ = 0;
60 bool HasBody_ =
false;
61 bool Chunked_ =
false;
62 bool BodyConsumed_ =
false;
63 size_t CurrentChunkSize_ = 0;
64 std::function<TFuture<ssize_t>(
char*,
size_t)> BodyReader_;
65 std::function<TFuture<std::string>()> ChunkHeaderReader_;
66 std::string_view Method_;
68 std::string_view Version_;
124 : ServerSocket(std::move(serverSocket))
126 , Logger(std::move(logger))
131 auto clientSocket =
co_await ServerSocket.
Accept();
132 HandleClient(std::move(clientSocket));
141 co_return co_await byteReader.ReadSome(buffer, size);
145 co_return co_await byteReader.ReadUntil(
"\r\n");
149 co_return co_await clientSocket.
WriteSome(data, size);
152 std::string clientString = clientSocket.
RemoteAddr() ? clientSocket.
RemoteAddr()->ToString() :
"unknown";
156 auto header =
co_await byteReader.ReadUntil(
"\r\n\r\n");
157 TRequest request(std::move(header), bodyReader, chunkHeaderReader);
159 co_await Router.HandleRequest(request, response);
160 Log(request, response, clientString);
161 if (response.IsClosed() || request.RequireConnectionClose()) {
165 }
catch (
const std::exception& ex) {
167 Logger(std::string(
"Client handler exception: ") + ex.what());
173 void Log(
const TRequest& request,
const TResponse& response,
const std::string& clientString) {
181 std::string fullPath = request.Uri().Path();
182 const auto& qp = request.Uri().QueryParameters();
184 fullPath.push_back(
'?');
186 for (
const auto& [k,v] : qp) {
187 if (!first) fullPath.push_back(
'&');
190 fullPath.push_back(
'=');
196 auto now = std::chrono::system_clock::now();
197 std::time_t raw = std::chrono::system_clock::to_time_t(now);
201 localtime_s(&localTm, &raw);
202 gmtime_s(&gmTm, &raw);
204 localtime_r(&raw, &localTm);
205 gmtime_r(&raw, &gmTm);
209 std::time_t localTime = std::mktime(&localTm);
210 std::time_t gmTime = std::mktime(&gmTm);
211 long tzOffsetSec =
static_cast<long>(difftime(localTime, gmTime));
212 int tzSign = tzOffsetSec >= 0 ? 1 : -1;
213 tzOffsetSec = std::labs(tzOffsetSec);
214 int tzHours =
static_cast<int>(tzOffsetSec / 3600);
215 int tzMins =
static_cast<int>((tzOffsetSec % 3600) / 60);
217 std::snprintf(tzBuf,
sizeof(tzBuf),
"%c%02d%02d", tzSign > 0 ?
'+' :
'-', tzHours, tzMins);
220 std::string_view ver = request.Version();
221 bool hasHttpPrefix = ver.size() >= 5 && ver.substr(0,5) ==
"HTTP/";
223 LogStream << clientString <<
" - - [" << std::put_time(&localTm,
"%d/%b/%Y:%H:%M:%S ") << tzBuf <<
"] \""
224 << request.Method() <<
' ' << fullPath <<
' ' << (hasHttpPrefix ? std::string(ver) : (std::string(
"HTTP/") + std::string(ver))) <<
"\" "
225 << response.StatusCode() <<
' ' <<
'-' <<
' ' <<
"\"-\" \"-\"";
226 Logger(LogStream.str());
231 std::function<void(
const std::string&)> Logger;
232 std::ostringstream LogStream;
auto WriteSome(const void *buf, size_t size)
Asynchronously writes data from the provided buffer to the socket.
Definition socket.hpp:189
const std::optional< TAddress > & RemoteAddr() const
Returns the remote address of the connected peer.
Definition socket.cpp:109
A utility for reading data from a socket-like object, either a fixed number of bytes or until a speci...
Definition sockutils.hpp:64