(strm);
StreamReader reader(bStrm);
ServerContext ctx(bStrm);
ctx.ip = ip;
ctx.port = port;
ctx.encrypted = encrypted;
ctx.serverPort = serverPort;
try {
bool firstLine = true;
std::string line;
while (reader.ReadLineHttp(line)) {
if (firstLine) {
auto v = HttpUtils::SplitString(line, " ", 3);
if (v.size() != 3) {
ctx.statusCode = BadRequest;
ctx.WithMimeType("text/plain")
.SendText("First line is not 3 elements");
return;
}
if (v[0] == "TRACE") {
std::string httpdata = line + "\r\n";
line.clear();
while (reader.ReadLineHttp(line)) {
httpdata += line + "\r\n";
line.clear();
}
ctx.WithMimeType("message/http").SendText(httpdata);
return;
}
ctx.method = v[0];
auto pp = HttpUtils::SplitString(v[1], "?", 2);
pp.resize(2);
ctx.originalPath = pp[0];
ctx.path = ctx.originalPath;
TF_LOG(ctx.method + " with path " + ctx.path);
auto queryPart = pp[1];
if (!queryPart.empty()) {
HttpUtils::QueryParamsDecode(ctx.queryParams, queryPart);
}
ctx.version = v[2];
} else {
auto v = HttpUtils::SplitString(line, ": ", 2);
if (v.size() != 2) {
ctx.statusCode = BadRequest;
ctx.WithMimeType("text/plain")
.SendText("Header line is not 2 elements");
return;
}
ctx.requestHeaders.AddValue(v[0], v[1]);
}
line.clear();
firstLine = false;
}
if (firstLine)
return;
std::string type;
int64_t length;
for (auto &item : ONLY_ONE_OF_THESE) {
if (ctx.requestHeaders.kvp.count(item) > 1) {
ctx.statusCode = StatusCode::BadRequest;
ctx.SendText(
""
""
"400 Bad "
"Request"
""
"400 Bad Request
" +
HttpUtils::HtmlEncode(
"There are multiple instances of the header \"" + item +
"\".") +
"
"
""
""
);
return;
}
}
if (!(ctx.method == "GET" || ctx.method == "HEAD") &&
ctx.requestHeaders.TryGetFirst("Content-Type", type) &&
type == "application/x-www-form-urlencoded" &&
ctx.requestHeaders.TryGetFirstInt("Content-Length", length)) {
if (length <= 0) {
ctx.statusCode = StatusCode::BadRequest;
ctx.SendErrorPage(true);
return;
}
size_t len = (size_t)length;
std::vector buffer(len);
len = bStrm->ReadBlock(buffer.data(), len);
std::string query((const char *)buffer.data(), len);
HttpUtils::QueryParamsDecode(ctx.bodyParams, query);
}
if (!server->Handle(ctx)) {
if ((int)ctx.statusCode == 200)
ctx.SendNotFound();
else
ctx.SendErrorPage(true);
}
}
catch (std::exception &ex) {
ctx.SendException(ex);
} catch (std::string &ex) {
std::runtime_error re(ex);
ctx.SendException(re);
} catch (const char *ex) {
std::runtime_error re(ex);
ctx.SendException(re);
} catch (...) {
std::runtime_error ex("An unknown error occurred");
ctx.SendException(ex);
}
}
bool ServerContext::Debug() { return this->debug; }
ServerContext &ServerContext::WithDebug(bool debug) {
this->debug = debug;
return *this;
}
WebSocketConnection::~WebSocketConnection() {}
void ServerContext::StartWebSocketSession(
std::function,
std::function, std::function)>
onOpen,
std::function onReceive,
std::function onClose) {
std::shared_ptr wsc =
std::make_shared(onOpen, onReceive,
onClose);
StartWebSocketSession(wsc);
}
void ServerContext::StartWebSocketSession(
std::shared_ptr connection) {
WSServer svr(this, connection);
Threading::Thread thrd([&svr, &connection]() -> void {
try {
connection->OnOpen(
[&svr](WebSocketMessage &msg) -> void { svr.send_msg(&msg); },
[&svr]() -> void {
std::vector p = {(uint8_t)'p', (uint8_t)'i',
(uint8_t)'n', (uint8_t)'g'};
svr.ping_send(p);
},
[&svr]() -> void { svr.close(); });
} catch (...) {
}
});
svr.Start();
thrd.Join();
}
std::string ServerContext::GetServerRoot() {
if (this->originalPath == this->path)
return "/";
Tesses::Framework::Filesystem::VFSPath originalPath = this->originalPath;
Tesses::Framework::Filesystem::VFSPath path = this->path;
if (originalPath.path.size() <= path.path.size())
return "/";
originalPath.path.resize(originalPath.path.size() - path.path.size());
return originalPath.ToString();
}
std::string ServerContext::MakeAbsolute(std::string path) {
if (path.find("http://") == 0 || path.find("https://") == 0 ||
path.find("/") == 0)
return path;
Tesses::Framework::Filesystem::VFSPath path2 = GetServerRoot();
path2 = path2 / path;
return path2.CollapseRelativeParents().ToString();
}
} // namespace Tesses::Framework::Http