๐Ÿ A very simple static Gemini server, now with Titan support!
cpp gemini titan gemini-protocol titan-protocol
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(maple.cc): Handle rapid reconnects without crashing on SIGPIPE

Fuwn f47e790c eeea40d4

+75 -54
+75 -54
maple/maple.cc
··· 63 63 close(maple::maple_socket); 64 64 SSL_CTX_free(maple::ssl_context); 65 65 }); 66 + signal(SIGPIPE, SIG_IGN); 66 67 67 68 // Find and keep track of all Gemini files to serve 68 69 for (const std::filesystem::directory_entry &entry : ··· 114 115 std::stringstream response; 115 116 std::size_t index_of_junk; 116 117 int request_scheme; // Gemini = 1, Titan = 2, Error = 0 117 - std::size_t bytes_read; 118 + std::size_t bytes_read = 0; 118 119 constexpr std::size_t GEMINI_MAXIMUM_REQUEST_SIZE = 1024; 119 120 std::array<char, GEMINI_MAXIMUM_REQUEST_SIZE> request{}; 121 + const int read_result = 122 + SSL_read_ex(ssl, request.begin(), request.size(), &bytes_read); 120 123 121 - SSL_read_ex(ssl, request.begin(), request.size(), &bytes_read); 122 - std::string path(request.data(), bytes_read); 124 + if (read_result > 0 && bytes_read > 0) { 125 + std::string path(request.data(), bytes_read); 126 + 127 + if (path.starts_with("gemini://")) { 128 + request_scheme = 1; 129 + } else if (path.starts_with("titan://")) { 130 + request_scheme = 2; 131 + } else { 132 + request_scheme = 0; 133 + } 123 134 124 - if (path.starts_with("gemini://")) { 125 - request_scheme = 1; 126 - } else if (path.starts_with("titan://")) { 127 - request_scheme = 2; 128 - } else { 129 - request_scheme = 0; 130 - } 135 + if (request_scheme != 0) { 136 + bool request_valid = true; 137 + 138 + // Remove "\r\n" if Gemini 139 + if (request_scheme == 1) { 140 + if (path.size() < 2) { 141 + std::cout << "received malformed gemini request\n"; 142 + 143 + request_valid = false; 144 + } else { 145 + path.resize(path.size() - 2); 146 + } 147 + } 148 + 149 + if (request_valid) { 150 + if (request_scheme == 1) { 151 + constexpr std::size_t GEMINI_PROTOCOL_LENGTH = 9; 131 152 132 - if (request_scheme != 0) { 133 - // Remove "\r\n" if Gemini 134 - if (request_scheme == 1) { 135 - path.resize(path.size() - 2); 136 - } 153 + path.erase(0, GEMINI_PROTOCOL_LENGTH); // Remove "gemini://" 154 + } else { 155 + constexpr std::size_t TITAN_PROTOCOL_LENGTH = 8; 137 156 138 - if (request_scheme == 1) { 139 - constexpr std::size_t GEMINI_PROTOCOL_LENGTH = 9; 157 + path.erase(0, TITAN_PROTOCOL_LENGTH); // Remove "titan://" 158 + } 140 159 141 - path.erase(0, GEMINI_PROTOCOL_LENGTH); // Remove "gemini://" 142 - } else { 143 - constexpr std::size_t TITAN_PROTOCOL_LENGTH = 8; 160 + // Try to remove the host, if you cannot; it must be a trailing 161 + // slash-less hostname, so we will respond with the index. 162 + const std::size_t found_first = path.find_first_of('/'); 144 163 145 - path.erase(0, TITAN_PROTOCOL_LENGTH); // Remove "titan://" 146 - } 164 + if (found_first != std::string::npos) { 165 + path = path.substr(found_first, 166 + path.size() - 1); // Remove host 167 + } else { 168 + path = "/index.gmi"; 169 + } 147 170 148 - // Try to remove the host, if you cannot; it must be a trailing 149 - // slash-less hostname, so we will respond with the index. 150 - const std::size_t found_first = path.find_first_of('/'); 171 + if (request_scheme == 1) { 172 + // Remove junk, if any 173 + index_of_junk = path.find_first_of('\n'); 151 174 152 - if (found_first != std::string::npos) { 153 - path = path.substr(found_first, 154 - path.size() - 1); // Remove host 155 - } else { 156 - path = "/index.gmi"; 157 - } 175 + if (index_of_junk != std::string::npos) { 176 + path.erase(path.find_first_of('\n') - 1, path.size() - 1); 177 + } 178 + } 158 179 159 - if (request_scheme == 1) { 160 - // Remove junk, if any 161 - index_of_junk = path.find_first_of('\n'); 180 + // Gemini 181 + if (request_scheme == 1) { 182 + maple::gemini::handle_client(gemini_files, path, response); 183 + } else { // Titan 184 + if (!titan) { 185 + response 186 + << "20 text/gemini\r\nThe server (Maple) does not have " 187 + "Titan support enabled!"; 188 + } else { 189 + maple::titan::handle_client(response, path, titan_token, 190 + titan_max_size); 191 + } 192 + } 162 193 163 - if (index_of_junk != std::string::npos) { 164 - path.erase(path.find_first_of('\n') - 1, path.size() - 1); 165 - } 166 - } 194 + const std::string response_string = response.str(); 195 + const int bytes_written = 196 + SSL_write(ssl, response_string.c_str(), 197 + static_cast<int>(response_string.size())); 167 198 168 - // Gemini 169 - if (request_scheme == 1) { 170 - maple::gemini::handle_client(gemini_files, path, response); 171 - } else { // Titan 172 - if (!titan) { 173 - response << "20 text/gemini\r\nThe server (Maple) does not have " 174 - "Titan support enabled!"; 175 - } else { 176 - maple::titan::handle_client(response, path, titan_token, 177 - titan_max_size); 199 + if (bytes_written <= 0) { 200 + ERR_print_errors_fp(stderr); 201 + } 178 202 } 203 + } else { 204 + std::cout << "received a request with an unsupported url scheme\n"; 179 205 } 180 - 181 - const std::string response_string = response.str(); 182 - 183 - SSL_write(ssl, response_string.c_str(), 184 - static_cast<int>(response_string.size())); 185 206 } else { 186 - std::cout << "received a request with an unsupported url scheme\n"; 207 + ERR_print_errors_fp(stderr); 187 208 } 188 209 } 189 210