Skip to content

Commit a568c6a

Browse files
committed
clean up HTTP server
1 parent 36e1f04 commit a568c6a

2 files changed

Lines changed: 56 additions & 46 deletions

File tree

Source/IO/HTTPServer.cpp

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -34,38 +34,35 @@ namespace IO
3434
std::size_t pos = c.msg.find(EOF_MSG);
3535
while (pos != std::string::npos)
3636
{
37-
// Check if this is a POST request with Content-Length
38-
std::size_t content_length = 0;
39-
std::size_t cl_pos = c.msg.find("Content-Length:");
40-
if (cl_pos == std::string::npos)
41-
cl_pos = c.msg.find("content-length:");
37+
// Lowercase the header region and find Content-Length anchored to a line start.
38+
// The request line is always first, so the header (if present) follows "\r\n".
39+
std::string headers(c.msg, 0, pos);
40+
Util::Convert::toLower(headers);
4241

43-
if (cl_pos != std::string::npos && cl_pos < pos)
42+
std::size_t content_length = 0;
43+
std::size_t cl_pos = headers.find("\r\ncontent-length:");
44+
if (cl_pos != std::string::npos)
4445
{
45-
std::size_t cl_end = c.msg.find("\r\n", cl_pos);
46-
if (cl_end != std::string::npos)
46+
std::size_t vs = cl_pos + 17;
47+
std::size_t ve = c.msg.find("\r\n", vs);
48+
std::string cl_value = c.msg.substr(vs, ve - vs);
49+
cl_value.erase(0, cl_value.find_first_not_of(" \t"));
50+
try
4751
{
48-
std::string cl_value = c.msg.substr(cl_pos + 15, cl_end - cl_pos - 15);
49-
// Trim whitespace
50-
cl_value.erase(0, cl_value.find_first_not_of(" \t"));
51-
try
52-
{
53-
content_length = std::stoul(cl_value);
54-
// Limit maximum content length to 1MB
55-
if (content_length > 1024 * 1024)
56-
{
57-
Error() << "Server: closing connection, Content-Length too large: " << content_length;
58-
c.Close();
59-
break;
60-
}
61-
}
62-
catch (...)
52+
content_length = std::stoul(cl_value);
53+
if (content_length > 1024 * 1024)
6354
{
64-
Error() << "Server: closing connection, invalid Content-Length: " << cl_value;
55+
Error() << "Server: closing connection, Content-Length too large: " << content_length;
6556
c.Close();
6657
break;
6758
}
6859
}
60+
catch (...)
61+
{
62+
Error() << "Server: closing connection, invalid Content-Length: " << cl_value;
63+
c.Close();
64+
break;
65+
}
6966
}
7067

7168
// Calculate how much data we need (headers + body)
@@ -120,11 +117,16 @@ namespace IO
120117
std::istringstream iss(s);
121118
std::string line;
122119
bool is_post = false;
123-
int content_length = 0;
120+
std::size_t content_length = 0;
124121
std::string url;
125122

126-
while (std::getline(iss, line) && !line.empty())
123+
while (std::getline(iss, line))
127124
{
125+
if (!line.empty() && line.back() == '\r')
126+
line.pop_back();
127+
if (line.empty())
128+
break;
129+
128130
std::istringstream line_stream(line);
129131
std::string key, value;
130132
std::getline(line_stream, key, ' ');
@@ -151,8 +153,8 @@ namespace IO
151153
std::getline(line_stream, value);
152154
try
153155
{
154-
content_length = std::stoi(value);
155-
if (content_length < 0 || content_length > 1024 * 1024)
156+
content_length = std::stoul(value);
157+
if (content_length > 1024 * 1024)
156158
{
157159
content_length = 0;
158160
}
@@ -217,7 +219,7 @@ namespace IO
217219

218220
if (cache)
219221
{
220-
header += "\r\nCache-Control: max-age=14187, stale-while-revalidate=604800, stale-if-error=604800";
222+
header += "\r\nCache-Control: max-age=31536000, stale-while-revalidate=604800, stale-if-error=604800";
221223
time_t now = time(0) + 31536000;
222224
char buf[100];
223225
strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now));

Source/IO/HTTPServer.h

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class SSEConnection
7373
headers += "Content-Type: text/event-stream\r\n";
7474
headers += "Cache-Control: no-cache\r\n";
7575
headers += "X-Accel-Buffering: no\r\n";
76-
headers += "Connection: keep-alive\r\n\r\n\r\n";
76+
headers += "Connection: keep-alive\r\n\r\n";
7777

7878
connection->SendDirect(headers.c_str(), headers.length());
7979
}
@@ -88,7 +88,7 @@ class SSEConnection
8888

8989
if (connection)
9090
{
91-
connection->SendDirect("\r\n", 1);
91+
connection->SendDirect("\r\n", 2);
9292
connection->Unlock();
9393
connection->Close();
9494
connection = nullptr;
@@ -124,23 +124,14 @@ class SSEConnection
124124

125125
void cleanupSSE()
126126
{
127-
for (auto it = sse.begin(); it != sse.end();)
128-
{
129-
if (!it->isConnected())
130-
{
131-
it->Close();
132-
it = sse.erase(it);
133-
}
134-
else
135-
{
136-
++it;
137-
}
138-
}
127+
std::lock_guard<std::mutex> lk(sse_mtx);
128+
cleanupSSE_locked();
139129
}
140130

141131
IO::SSEConnection *upgradeSSE(IO::TCPServerConnection &c, int id)
142132
{
143-
cleanupSSE();
133+
std::lock_guard<std::mutex> lk(sse_mtx);
134+
cleanupSSE_locked();
144135

145136
sse.emplace_back(&c, id);
146137
auto &connection = sse.back();
@@ -150,18 +141,35 @@ class SSEConnection
150141

151142
void sendSSE(int id, const std::string &event, const std::string &data)
152143
{
153-
144+
std::lock_guard<std::mutex> lk(sse_mtx);
154145
for (auto it = sse.begin(); it != sse.end(); ++it)
155146
{
156147
if (it->getID() == id)
157148
it->SendEvent(sse_topic[MIN(id, 3)], data);
158149
}
159-
cleanupSSE();
150+
cleanupSSE_locked();
160151
}
161152

162153
private:
163154
std::string ret, header;
164155
std::list<IO::SSEConnection> sse;
156+
std::mutex sse_mtx;
157+
158+
void cleanupSSE_locked()
159+
{
160+
for (auto it = sse.begin(); it != sse.end();)
161+
{
162+
if (!it->isConnected())
163+
{
164+
it->Close();
165+
it = sse.erase(it);
166+
}
167+
else
168+
{
169+
++it;
170+
}
171+
}
172+
}
165173

166174
void Parse(const std::string &s, std::string &get, bool &accept_gzip);
167175
void processClients();

0 commit comments

Comments
 (0)