diff options
| -rw-r--r-- | maple/gemini.cc | 40 | ||||
| -rw-r--r-- | maple/gemini.hh | 11 | ||||
| -rw-r--r-- | maple/maple.cc | 246 | ||||
| -rw-r--r-- | maple/maple.hh | 13 | ||||
| -rw-r--r-- | maple/titan.cc | 234 | ||||
| -rw-r--r-- | maple/titan.hh | 23 |
6 files changed, 261 insertions, 306 deletions
diff --git a/maple/gemini.cc b/maple/gemini.cc index af6d194..83ad3ee 100644 --- a/maple/gemini.cc +++ b/maple/gemini.cc @@ -23,31 +23,27 @@ #include "gemini.hh" -namespace maple::gemini { - auto handle_client( - std::vector<std::string> gemini_files, - std::string path, - std::stringstream &response - ) -> void { - // Check if the route is a file being served - if (std::find( - gemini_files.begin(), - gemini_files.end(), - ".maple/gmi" + path - ) != gemini_files.end()) { - // If the route is a file being served; get the file contents +namespace maple { +namespace gemini { +auto handle_client(std::vector<std::string> gemini_files, std::string path, + std::stringstream &response) -> void { + // Check if the route is a file being served + if (std::find(gemini_files.begin(), gemini_files.end(), + ".maple/gmi" + path) != gemini_files.end()) { + // If the route is a file being served; get the file contents + response << "20 text/gemini\r\n" + << std::ifstream(".maple/gmi" + path).rdbuf(); + } else { + if (path.empty() || path.at(path.length() - 1) == '/') { response << "20 text/gemini\r\n" - << std::ifstream(".maple/gmi" + path).rdbuf(); + << std::ifstream(".maple/gmi" + path + "index.gmi").rdbuf(); } else { - if (path.empty() || path.at(path.length() - 1) == '/') { - response << "20 text/gemini\r\n" - << std::ifstream(".maple/gmi" + path + "index.gmi").rdbuf(); - } else { - response + response << "51 The server (Maple) could not find the specified file.\r\n"; - } } - - std::cout << "requested " << path << std::endl; } + + std::cout << "requested " << path << std::endl; } +} // namespace gemini +} // namespace maple diff --git a/maple/gemini.hh b/maple/gemini.hh index 35a23e6..e270504 100644 --- a/maple/gemini.hh +++ b/maple/gemini.hh @@ -24,12 +24,11 @@ #include <sstream> #include <vector> -namespace maple::gemini { - auto handle_client( - std::vector<std::string>, - std::string, - std::stringstream & - ) -> void; +namespace maple { +namespace gemini { +auto handle_client(std::vector<std::string>, std::string, std::stringstream &) + -> void; } +} // namespace maple #endif // GEMINI_HH diff --git a/maple/maple.cc b/maple/maple.cc index 8f5dd38..45e5ac1 100644 --- a/maple/maple.cc +++ b/maple/maple.cc @@ -54,20 +54,16 @@ auto main() -> int { // Find and keep track of all Gemini files to serve for (const std::filesystem::directory_entry &entry : - std::filesystem::recursive_directory_iterator(".maple/gmi")) - { + std::filesystem::recursive_directory_iterator(".maple/gmi")) { std::string file_extension = entry.path().string().substr( - entry.path().string().find_last_of('.') + 1 - ); + entry.path().string().find_last_of('.') + 1); // Only keep track of file if it is a Gemini file - if (std::equal( - file_extension.begin(), - file_extension.end(), - GEMINI_FILE_EXTENSION.begin(), - GEMINI_FILE_EXTENSION.end(), - [](char a, char b) -> bool { return std::tolower(a) == std::tolower(b); } - )) { + if (std::equal(file_extension.begin(), file_extension.end(), + GEMINI_FILE_EXTENSION.begin(), GEMINI_FILE_EXTENSION.end(), + [](char a, char b) -> bool { + return std::tolower(a) == std::tolower(b); + })) { gemini_files.push_back(entry.path()); } } @@ -78,18 +74,18 @@ auto main() -> int { } // Setup SSL - if (maple::setup_ssl() == EXIT_FAILURE) { return EXIT_FAILURE; } + if (maple::setup_ssl() == EXIT_FAILURE) { + return EXIT_FAILURE; + } // Listen and serve connections for (;;) { - sockaddr_in socket_address_ {}; + sockaddr_in socket_address_{}; unsigned int socket_address_length = sizeof(socket_address_); SSL *ssl; - int client = accept( - maple::maple_socket, - reinterpret_cast<sockaddr *>(&socket_address_), - &socket_address_length - ); + int client = accept(maple::maple_socket, + reinterpret_cast<sockaddr *>(&socket_address_), + &socket_address_length); if (client < 0) { return maple::prepare_exit_with("unable to accept", false); @@ -106,7 +102,7 @@ auto main() -> int { size_t index_of_junk; int request_scheme; // Gemini = 1, Titan = 2, Error = 0 size_t bytes_read; - char request[1024] {}; + char request[1024]{}; SSL_read_ex(ssl, request, sizeof(request), &bytes_read); @@ -139,10 +135,8 @@ auto main() -> int { size_t found_first = path.find_first_of('/'); if (found_first != std::string::npos) { - path = path.substr( - found_first, - path.size() - 1 - ); // Remove host + path = path.substr(found_first, + path.size() - 1); // Remove host } else { path = "/index.gmi"; } @@ -152,10 +146,7 @@ auto main() -> int { 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 - ); + path.erase(path.find_first_of('\n') - 1, path.size() - 1); } } @@ -167,23 +158,16 @@ auto main() -> int { 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 - ); + maple::titan::handle_client(response, path, titan_token, + titan_max_size); } } - SSL_write( - ssl, - response.str().c_str(), - static_cast<int>(response.str().size()) - ); + SSL_write(ssl, response.str().c_str(), + static_cast<int>(response.str().size())); } else { std::cout << "received a request with an unsupported url scheme" - << std::endl; + << std::endl; } } @@ -194,129 +178,113 @@ auto main() -> int { } namespace maple { - auto prepare_exit_with(const char *message, bool ssl) -> int { - perror(message); - - if (ssl) { ERR_print_errors_fp(stderr); } +auto prepare_exit_with(const char *message, bool ssl) -> int { + perror(message); - return EXIT_FAILURE; + if (ssl) { + ERR_print_errors_fp(stderr); } - auto setup_environment( - bool &titan, - std::string &titan_token, - size_t &titan_max_size - ) -> int { - char *titan_environment = std::getenv("TITAN"); + return EXIT_FAILURE; +} - if (titan_environment == nullptr) { - titan = false; - } else { - std::string valid_titan_environment(titan_environment); +auto setup_environment(bool &titan, std::string &titan_token, + size_t &titan_max_size) -> int { + char *titan_environment = std::getenv("TITAN"); - std::transform( - valid_titan_environment.begin(), - valid_titan_environment.end(), - valid_titan_environment.begin(), - [](unsigned char c) -> int { return std::tolower(c); } - ); + if (titan_environment == nullptr) { + titan = false; + } else { + std::string valid_titan_environment(titan_environment); - if (valid_titan_environment == "true" || valid_titan_environment == "1") { - char *unvalidated_titan_token = std::getenv("TITAN_TOKEN"); - char *unvalidated_titan_max_size = std::getenv("TITAN_MAX_SIZE"); + std::transform(valid_titan_environment.begin(), + valid_titan_environment.end(), + valid_titan_environment.begin(), + [](unsigned char c) -> int { return std::tolower(c); }); - if (unvalidated_titan_token == nullptr) { - titan_token = ""; - } else { - titan_token = std::string(unvalidated_titan_token); - } + if (valid_titan_environment == "true" || valid_titan_environment == "1") { + char *unvalidated_titan_token = std::getenv("TITAN_TOKEN"); + char *unvalidated_titan_max_size = std::getenv("TITAN_MAX_SIZE"); + + if (unvalidated_titan_token == nullptr) { + titan_token = ""; + } else { + titan_token = std::string(unvalidated_titan_token); + } - if (unvalidated_titan_max_size == nullptr) { - titan_max_size = 1024; + if (unvalidated_titan_max_size == nullptr) { + titan_max_size = 1024; - std::cout << "no TITAN_MAX_SIZE set, defaulting to 1024" << std::endl; - } else { - try { - titan_max_size = static_cast<size_t>( - std::stoi(unvalidated_titan_max_size) - ); - } catch (...) { - return maple::prepare_exit_with( - "TITAN_MAX_SIZE could not be interpreted as an integer", - false - ); - } + std::cout << "no TITAN_MAX_SIZE set, defaulting to 1024" << std::endl; + } else { + try { + titan_max_size = + static_cast<size_t>(std::stoi(unvalidated_titan_max_size)); + } catch (...) { + return maple::prepare_exit_with( + "TITAN_MAX_SIZE could not be interpreted as an integer", false); } - - titan = true; } - } - return 0; + titan = true; + } } - auto setup_ssl() -> int { - sockaddr_in socket_address {}; + return 0; +} - // Setup OpenSSL - SSL_library_init(); - SSL_load_error_strings(); +auto setup_ssl() -> int { + sockaddr_in socket_address{}; - maple::ssl_context = SSL_CTX_new(TLS_server_method()); + // Setup OpenSSL + SSL_library_init(); + SSL_load_error_strings(); - if (!maple::ssl_context) { - return maple::prepare_exit_with("unable to create ssl context", true); - } + maple::ssl_context = SSL_CTX_new(TLS_server_method()); - if (SSL_CTX_use_certificate_file( - maple::ssl_context, - ".maple/public.pem", - SSL_FILETYPE_PEM - ) <= 0) { - return maple::prepare_exit_with("unable to use certificate file", true); - } - if (SSL_CTX_use_PrivateKey_file( - maple::ssl_context, - ".maple/private.pem", - SSL_FILETYPE_PEM - ) <= 0) { - return maple::prepare_exit_with("unable to use private key file", true); - } + if (!maple::ssl_context) { + return maple::prepare_exit_with("unable to create ssl context", true); + } - socket_address.sin_family = AF_INET; - socket_address.sin_port = htons(1965); - socket_address.sin_addr.s_addr = htonl(INADDR_ANY); + if (SSL_CTX_use_certificate_file(maple::ssl_context, ".maple/public.pem", + SSL_FILETYPE_PEM) <= 0) { + return maple::prepare_exit_with("unable to use certificate file", true); + } - maple::maple_socket = socket(AF_INET, SOCK_STREAM, 0); + if (SSL_CTX_use_PrivateKey_file(maple::ssl_context, ".maple/private.pem", + SSL_FILETYPE_PEM) <= 0) { + return maple::prepare_exit_with("unable to use private key file", true); + } - if (maple::maple_socket < 0) { - return maple::prepare_exit_with("unable to create socket", false); - } + socket_address.sin_family = AF_INET; + socket_address.sin_port = htons(1965); + socket_address.sin_addr.s_addr = htonl(INADDR_ANY); - // Reuse address. Allows the use of the address instantly after a SIGINT - // without having to wait for the socket to die. - int reuse_addr = 1; - if (setsockopt( - maple::maple_socket, - SOL_SOCKET, - SO_REUSEADDR, - &reuse_addr, - sizeof(int) - ) < 0) { - return maple::prepare_exit_with("unable to set socket options (SO_LINGER)", false); - } + maple::maple_socket = socket(AF_INET, SOCK_STREAM, 0); - if (bind( - maple::maple_socket, - reinterpret_cast<sockaddr *>(&socket_address), - sizeof(socket_address) - ) < 0) { - return maple::prepare_exit_with("unable to bind", false); - } - if (listen(maple::maple_socket, 1) < 0) { - return maple::prepare_exit_with("unable to listen", false); - } + if (maple::maple_socket < 0) { + return maple::prepare_exit_with("unable to create socket", false); + } + + // Reuse address. Allows the use of the address instantly after a SIGINT + // without having to wait for the socket to die. + int reuse_addr = 1; + + if (setsockopt(maple::maple_socket, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, + sizeof(int)) < 0) { + return maple::prepare_exit_with("unable to set socket options (SO_LINGER)", + false); + } + + if (bind(maple::maple_socket, reinterpret_cast<sockaddr *>(&socket_address), + sizeof(socket_address)) < 0) { + return maple::prepare_exit_with("unable to bind", false); + } - return 0; + if (listen(maple::maple_socket, 1) < 0) { + return maple::prepare_exit_with("unable to listen", false); } + + return 0; } +} // namespace maple diff --git a/maple/maple.hh b/maple/maple.hh index 841eb71..5f72357 100644 --- a/maple/maple.hh +++ b/maple/maple.hh @@ -22,14 +22,15 @@ #define MAPLE_HH #include <openssl/ssl.h> +#include <string> namespace maple { - static int maple_socket; - static SSL_CTX *ssl_context; +static int maple_socket; +static SSL_CTX *ssl_context; - auto prepare_exit_with(const char *, bool) -> int; - auto setup_environment(bool &, std::string &, size_t &) -> int; - auto setup_ssl() -> int; -} +auto prepare_exit_with(const char *, bool) -> int; +auto setup_environment(bool &, std::string &, size_t &) -> int; +auto setup_ssl() -> int; +} // namespace maple #endif // MAPLE_HH diff --git a/maple/titan.cc b/maple/titan.cc index 2ae32a4..7f838f3 100644 --- a/maple/titan.cc +++ b/maple/titan.cc @@ -18,151 +18,143 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include <map> #include <fstream> +#include <map> #include <vector> #include "titan.hh" -namespace maple::titan { - auto parameters_to_map( - const std::vector<std::string> ¶meters - ) -> std::map<std::string, std::string> { - std::map<std::string, std::string> parameters_map; - - for (auto parameter : parameters) { - // Find the key in `parameter` - size_t parameter_delimiter_position = parameter.find('='); - std::string key = parameter.substr( - 0, - parameter_delimiter_position - ); - - // Remove the key in `parameter` - parameter.erase(0, parameter_delimiter_position + 1); - - // Add the key and value to `parameters_map` - parameters_map[key] = parameter; - } +namespace maple { +namespace titan { +auto parameters_to_map(const std::vector<std::string> ¶meters) + -> std::map<std::string, std::string> { + std::map<std::string, std::string> parameters_map; + + for (auto parameter : parameters) { + // Find the key in `parameter` + size_t parameter_delimiter_position = parameter.find('='); + std::string key = parameter.substr(0, parameter_delimiter_position); + + // Remove the key in `parameter` + parameter.erase(0, parameter_delimiter_position + 1); - return parameters_map; + // Add the key and value to `parameters_map` + parameters_map[key] = parameter; } - auto handle_client( - std::stringstream &response, - std::string path, - const std::string &titan_token, - size_t titan_max_size - ) -> void { - std::vector<std::string> parameters; - // Find path in `path` - size_t delimiter_position = path.find(';'); - std::string update_path = path.substr(0, delimiter_position); - std::string body = path.substr(path.find('\n') + 1, path.length() - 1); - - path.erase(path.find('\n') - 1, path.length() - 1); - // parameters.push_back(update_path); - path.erase(0, delimiter_position + 1); // Remove path from `path` - - // Find mime parameter in `path` - delimiter_position = path.find(';'); - - parameters.push_back(path.substr(0, delimiter_position)); - path.erase(0, delimiter_position + 1); // Remove mime parameter from `path` - - // Find size parameter in `path` - delimiter_position = path.find(';'); - - parameters.push_back(path.substr(0, delimiter_position)); - - // Find token parameter in `path` - delimiter_position = path.find(';'); - - // Since the token is optional, only get and assign the token - // parameters value if it exists. - if (delimiter_position != std::string::npos) { - parameters.push_back(path.substr( - delimiter_position + 1, - path.length() - 1 - )); - } + return parameters_map; +} -/// Check if a parameter exists within a `std::vector` of Titan -/// parameters. - /* auto parameter_exists = []( - const std::vector<std::string> &_parameters, - const std::string ¶meter - ) -> bool { - return std::any_of( - _parameters.begin(), - _parameters.end(), - [&](const std::string &s) -> bool { - return s.find(parameter) != std::string::npos; - } - ); - }; */ - - std::map<std::string, std::string> parameters_map = - maple::titan::parameters_to_map(parameters); +auto handle_client(std::stringstream &response, std::string path, + const std::string &titan_token, size_t titan_max_size) + -> void { + std::vector<std::string> parameters; + // Find path in `path` + size_t delimiter_position = path.find(';'); + std::string update_path = path.substr(0, delimiter_position); + std::string body = path.substr(path.find('\n') + 1, path.length() - 1); - // Make sure all tokens have been supplied - for (;;) { - if (parameters_map.find("mime") == parameters_map.end()) { - response << "20 text/gemini\r\nThe serve (Maple) did not " - "receive a mime parameter!"; - break; - } - if (parameters_map.find("size") == parameters_map.end()) { - response << "20 text/gemini\r\nThe serve (Maple) did not " - "receive a size parameter!"; + path.erase(path.find('\n') - 1, path.length() - 1); + // parameters.push_back(update_path); + path.erase(0, delimiter_position + 1); // Remove path from `path` - break; - } - if (!titan_token.empty() - && parameters_map.find("token") == parameters_map.end()) - { - response << "20 text/gemini\r\nThe serve (Maple) did not " - "receive a token parameter!"; + // Find mime parameter in `path` + delimiter_position = path.find(';'); - break; - } + parameters.push_back(path.substr(0, delimiter_position)); + path.erase(0, delimiter_position + 1); // Remove mime parameter from `path` - try { - size_t body_size = static_cast<size_t>( - std::stoi(parameters_map["size"]) - ); + // Find size parameter in `path` + delimiter_position = path.find(';'); - if (body_size > titan_max_size) { - response << "20 text/gemini\r\nThe server (Maple) received a body " - << "which is larger than the maximum allowed body size (" - << titan_max_size << ")."; + parameters.push_back(path.substr(0, delimiter_position)); - break; - } - } catch (...) { - response << "20 text/gemini\r\nThe server (Maple) could not interpret " - "the size parameter as an integer!"; + // Find token parameter in `path` + delimiter_position = path.find(';'); - break; - } + // Since the token is optional, only get and assign the token + // parameters value if it exists. + if (delimiter_position != std::string::npos) { + parameters.push_back( + path.substr(delimiter_position + 1, path.length() - 1)); + } - if (update_path == "/") { - update_path = "/index.gmi"; + /// Check if a parameter exists within a `std::vector` of Titan + /// parameters. + /* auto parameter_exists = []( + const std::vector<std::string> &_parameters, + const std::string ¶meter + ) -> bool { + return std::any_of( + _parameters.begin(), + _parameters.end(), + [&](const std::string &s) -> bool { + return s.find(parameter) != std::string::npos; } + ); + }; */ + + std::map<std::string, std::string> parameters_map = + maple::titan::parameters_to_map(parameters); - if (parameters_map["token"] == titan_token) { - std::ofstream file(".maple/gmi" + update_path); + // Make sure all tokens have been supplied + for (;;) { + if (parameters_map.find("mime") == parameters_map.end()) { + response << "20 text/gemini\r\nThe serve (Maple) did not " + "receive a mime parameter!"; + break; + } + + if (parameters_map.find("size") == parameters_map.end()) { + response << "20 text/gemini\r\nThe serve (Maple) did not " + "receive a size parameter!"; + + break; + } + + if (!titan_token.empty() && + parameters_map.find("token") == parameters_map.end()) { + response << "20 text/gemini\r\nThe serve (Maple) did not " + "receive a token parameter!"; + + break; + } - file << body; + try { + size_t body_size = static_cast<size_t>(std::stoi(parameters_map["size"])); - response << "20 text/gemini\r\nSuccessfully wrote " - << body.length() << " bytes to " << update_path << '!'; - } else { - response << "20 text/gemini\r\nThe server (Maple) wrote to " - << update_path; + if (body_size > titan_max_size) { + response << "20 text/gemini\r\nThe server (Maple) received a body " + << "which is larger than the maximum allowed body size (" + << titan_max_size << ")."; + + break; } + } catch (...) { + response << "20 text/gemini\r\nThe server (Maple) could not interpret " + "the size parameter as an integer!"; break; } + + if (update_path == "/") { + update_path = "/index.gmi"; + } + + if (parameters_map["token"] == titan_token) { + std::ofstream file(".maple/gmi" + update_path); + + file << body; + + response << "20 text/gemini\r\nSuccessfully wrote " << body.length() + << " bytes to " << update_path << '!'; + } else { + response << "20 text/gemini\r\nThe server (Maple) wrote to " + << update_path; + } + + break; } } +} // namespace titan +} // namespace maple diff --git a/maple/titan.hh b/maple/titan.hh index 8895551..06a94da 100644 --- a/maple/titan.hh +++ b/maple/titan.hh @@ -21,20 +21,19 @@ #ifndef TITAN_HH #define TITAN_HH +#include <map> #include <sstream> +#include <vector> -namespace maple::titan { - /// Convert a `std::vector` of Titan parameters into a key/ value `std::map` - auto parameters_to_map( - const std::vector<std::string> & - ) -> std::map<std::string, std::string>; +namespace maple { +namespace titan { +/// Convert a `std::vector` of Titan parameters into a key/ value `std::map` +auto parameters_to_map(const std::vector<std::string> &) + -> std::map<std::string, std::string>; - auto handle_client( - std::stringstream &, - std::string, - const std::string &, - size_t - ) -> void; -} +auto handle_client(std::stringstream &, std::string, const std::string &, + size_t) -> void; +} // namespace titan +} // namespace maple #endif // TITAN_HH |