aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2025-12-06 08:18:01 +0000
committerFuwn <[email protected]>2025-12-06 08:18:01 +0000
commitf47e790ce107b01c8326435cc22d1df919a3dc54 (patch)
treeea00c6ecec93a00a3cddacab512196d0c1ab4840
parentrefactor: Optimise request handling and harden Titan parameter parsing (diff)
downloadmaple-f47e790ce107b01c8326435cc22d1df919a3dc54.tar.xz
maple-f47e790ce107b01c8326435cc22d1df919a3dc54.zip
fix(maple.cc): Handle rapid reconnects without crashing on SIGPIPEHEADmain
-rw-r--r--maple/maple.cc133
1 files changed, 77 insertions, 56 deletions
diff --git a/maple/maple.cc b/maple/maple.cc
index 71ad82f..426cc14 100644
--- a/maple/maple.cc
+++ b/maple/maple.cc
@@ -63,6 +63,7 @@ auto main() -> int {
close(maple::maple_socket);
SSL_CTX_free(maple::ssl_context);
});
+ signal(SIGPIPE, SIG_IGN);
// Find and keep track of all Gemini files to serve
for (const std::filesystem::directory_entry &entry :
@@ -114,76 +115,96 @@ auto main() -> int {
std::stringstream response;
std::size_t index_of_junk;
int request_scheme; // Gemini = 1, Titan = 2, Error = 0
- std::size_t bytes_read;
+ std::size_t bytes_read = 0;
constexpr std::size_t GEMINI_MAXIMUM_REQUEST_SIZE = 1024;
std::array<char, GEMINI_MAXIMUM_REQUEST_SIZE> request{};
+ const int read_result =
+ SSL_read_ex(ssl, request.begin(), request.size(), &bytes_read);
- SSL_read_ex(ssl, request.begin(), request.size(), &bytes_read);
- std::string path(request.data(), bytes_read);
+ if (read_result > 0 && bytes_read > 0) {
+ std::string path(request.data(), bytes_read);
- if (path.starts_with("gemini://")) {
- request_scheme = 1;
- } else if (path.starts_with("titan://")) {
- request_scheme = 2;
- } else {
- request_scheme = 0;
- }
-
- if (request_scheme != 0) {
- // Remove "\r\n" if Gemini
- if (request_scheme == 1) {
- path.resize(path.size() - 2);
- }
-
- if (request_scheme == 1) {
- constexpr std::size_t GEMINI_PROTOCOL_LENGTH = 9;
-
- path.erase(0, GEMINI_PROTOCOL_LENGTH); // Remove "gemini://"
+ if (path.starts_with("gemini://")) {
+ request_scheme = 1;
+ } else if (path.starts_with("titan://")) {
+ request_scheme = 2;
} else {
- constexpr std::size_t TITAN_PROTOCOL_LENGTH = 8;
-
- path.erase(0, TITAN_PROTOCOL_LENGTH); // Remove "titan://"
+ request_scheme = 0;
}
- // Try to remove the host, if you cannot; it must be a trailing
- // slash-less hostname, so we will respond with the index.
- const std::size_t found_first = path.find_first_of('/');
+ if (request_scheme != 0) {
+ bool request_valid = true;
- if (found_first != std::string::npos) {
- path = path.substr(found_first,
- path.size() - 1); // Remove host
- } else {
- path = "/index.gmi";
- }
+ // Remove "\r\n" if Gemini
+ if (request_scheme == 1) {
+ if (path.size() < 2) {
+ std::cout << "received malformed gemini request\n";
- if (request_scheme == 1) {
- // Remove junk, if any
- index_of_junk = path.find_first_of('\n');
-
- if (index_of_junk != std::string::npos) {
- path.erase(path.find_first_of('\n') - 1, path.size() - 1);
+ request_valid = false;
+ } else {
+ path.resize(path.size() - 2);
+ }
}
- }
- // Gemini
- if (request_scheme == 1) {
- maple::gemini::handle_client(gemini_files, path, response);
- } else { // Titan
- if (!titan) {
- response << "20 text/gemini\r\nThe server (Maple) does not have "
- "Titan support enabled!";
- } else {
- maple::titan::handle_client(response, path, titan_token,
- titan_max_size);
+ if (request_valid) {
+ if (request_scheme == 1) {
+ constexpr std::size_t GEMINI_PROTOCOL_LENGTH = 9;
+
+ path.erase(0, GEMINI_PROTOCOL_LENGTH); // Remove "gemini://"
+ } else {
+ constexpr std::size_t TITAN_PROTOCOL_LENGTH = 8;
+
+ path.erase(0, TITAN_PROTOCOL_LENGTH); // Remove "titan://"
+ }
+
+ // Try to remove the host, if you cannot; it must be a trailing
+ // slash-less hostname, so we will respond with the index.
+ const std::size_t found_first = path.find_first_of('/');
+
+ if (found_first != std::string::npos) {
+ path = path.substr(found_first,
+ path.size() - 1); // Remove host
+ } else {
+ path = "/index.gmi";
+ }
+
+ if (request_scheme == 1) {
+ // Remove junk, if any
+ index_of_junk = path.find_first_of('\n');
+
+ if (index_of_junk != std::string::npos) {
+ path.erase(path.find_first_of('\n') - 1, path.size() - 1);
+ }
+ }
+
+ // Gemini
+ if (request_scheme == 1) {
+ maple::gemini::handle_client(gemini_files, path, response);
+ } else { // Titan
+ if (!titan) {
+ response
+ << "20 text/gemini\r\nThe server (Maple) does not have "
+ "Titan support enabled!";
+ } else {
+ maple::titan::handle_client(response, path, titan_token,
+ titan_max_size);
+ }
+ }
+
+ const std::string response_string = response.str();
+ const int bytes_written =
+ SSL_write(ssl, response_string.c_str(),
+ static_cast<int>(response_string.size()));
+
+ if (bytes_written <= 0) {
+ ERR_print_errors_fp(stderr);
+ }
}
+ } else {
+ std::cout << "received a request with an unsupported url scheme\n";
}
-
- const std::string response_string = response.str();
-
- SSL_write(ssl, response_string.c_str(),
- static_cast<int>(response_string.size()));
} else {
- std::cout << "received a request with an unsupported url scheme\n";
+ ERR_print_errors_fp(stderr);
}
}