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;
49 void ParseRequestLine();
56 size_t HeaderStartPos_ = 0;
57 std::map<std::string_view, std::string_view> Headers_;
58 size_t ContentLength_ = 0;
59 bool HasBody_ =
false;
60 bool Chunked_ =
false;
61 bool BodyConsumed_ =
false;
62 size_t CurrentChunkSize_ = 0;
63 std::function<TFuture<ssize_t>(
char*,
size_t)> BodyReader_;
64 std::function<TFuture<std::string>()> ChunkHeaderReader_;
65 std::string_view Method_;
67 std::string_view Version_;
123 : ServerSocket(std::move(serverSocket))
125 , Logger(std::move(logger))
130 auto clientSocket =
co_await ServerSocket.
Accept();
131 HandleClient(std::move(clientSocket));
140 co_return co_await byteReader.ReadSome(buffer, size);
144 co_return co_await byteReader.ReadUntil(
"\r\n");
148 co_return co_await clientSocket.
WriteSome(data, size);
151 std::string clientString = clientSocket.
RemoteAddr() ? clientSocket.
RemoteAddr()->ToString() :
"unknown";
155 auto header =
co_await byteReader.ReadUntil(
"\r\n\r\n");
156 TRequest request(std::move(header), bodyReader, chunkHeaderReader);
158 co_await Router.HandleRequest(request, response);
159 Log(request, response, clientString);
160 if (response.IsClosed() || request.RequireConnectionClose()) {
164 }
catch (
const std::exception& ex) {
166 Logger(std::string(
"Client handler exception: ") + ex.what());
172 void Log(
const TRequest& request,
const TResponse& response,
const std::string& clientString) {
180 std::string fullPath = request.Uri().Path();
181 const auto& qp = request.Uri().QueryParameters();
183 fullPath.push_back(
'?');
185 for (
const auto& [k,v] : qp) {
186 if (!first) fullPath.push_back(
'&');
189 fullPath.push_back(
'=');
195 auto now = std::chrono::system_clock::now();
196 std::time_t raw = std::chrono::system_clock::to_time_t(now);
200 localtime_s(&localTm, &raw);
201 gmtime_s(&gmTm, &raw);
203 localtime_r(&raw, &localTm);
204 gmtime_r(&raw, &gmTm);
208 std::time_t localTime = std::mktime(&localTm);
209 std::time_t gmTime = std::mktime(&gmTm);
210 long tzOffsetSec =
static_cast<long>(difftime(localTime, gmTime));
211 int tzSign = tzOffsetSec >= 0 ? 1 : -1;
212 tzOffsetSec = std::labs(tzOffsetSec);
213 int tzHours =
static_cast<int>(tzOffsetSec / 3600);
214 int tzMins =
static_cast<int>((tzOffsetSec % 3600) / 60);
216 std::snprintf(tzBuf,
sizeof(tzBuf),
"%c%02d%02d", tzSign > 0 ?
'+' :
'-', tzHours, tzMins);
219 std::string_view ver = request.Version();
220 bool hasHttpPrefix = ver.size() >= 5 && ver.substr(0,5) ==
"HTTP/";
222 LogStream << clientString <<
" - - [" << std::put_time(&localTm,
"%d/%b/%Y:%H:%M:%S ") << tzBuf <<
"] \""
223 << request.Method() <<
' ' << fullPath <<
' ' << (hasHttpPrefix ? std::string(ver) : (std::string(
"HTTP/") + std::string(ver))) <<
"\" "
224 << response.StatusCode() <<
' ' <<
'-' <<
' ' <<
"\"-\" \"-\"";
225 Logger(LogStream.str());
230 std::function<void(
const std::string&)> Logger;
231 std::ostringstream LogStream;
auto WriteSome(const void *buf, size_t size)
Asynchronously writes data from the provided buffer to the socket.
Definition socket.hpp:186
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