diff options
author | cflip <cflip@cflip.net> | 2022-09-15 12:13:20 -0600 |
---|---|---|
committer | cflip <cflip@cflip.net> | 2022-09-15 12:13:20 -0600 |
commit | ac12ef846b343849317539c84258ab0c5e6b542f (patch) | |
tree | 075ce63eeb1a9facd653ef07f1537708bfba6464 | |
parent | 6266304977eb6bde01b374c53ca2a2a3514cb0d4 (diff) |
Add an option to serve CGI exectuables
-rw-r--r-- | src/main.cpp | 115 |
1 files changed, 82 insertions, 33 deletions
diff --git a/src/main.cpp b/src/main.cpp index 7cd4787..cec6d3e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,19 +9,95 @@ #include "HttpResponse.h" #include "ServerConnection.h" +static HttpResponse serve_from_filesystem(HttpRequest request) +{ + namespace fs = std::filesystem; + + HttpResponse response; + response.add_header("Server", "cfws"); + + // Remove leading slash from the path if it exists + std::string relative_request_path = request.uri(); + while (*relative_request_path.begin() == '/') + relative_request_path.erase(0, 1); + + fs::path request_path = fs::current_path() / relative_request_path; + + // Look for an index.html if the requested path is a directory + if (fs::is_directory(request_path)) { + request_path /= "index.html"; + } + + if (fs::exists(request_path)) { + std::string file_path = request_path.string(); + std::ifstream input_file(file_path); + if (!input_file.is_open()) { + std::cerr << "Failed to open file " << file_path << std::endl; + } + + std::string file_contents((std::istreambuf_iterator<char>(input_file)), std::istreambuf_iterator<char>()); + + response.set_status_code(HttpStatusCode::OK); + response.add_header("Content-Type", "text/plain"); + response.set_content(file_contents); + } else { + response.set_status_code(HttpStatusCode::NotFound); + response.add_header("Content-Type", "text/plain"); + response.set_content("Page not found!"); + } + + return response; +} + +static HttpResponse serve_from_cgi(const std::string& executable_path, HttpRequest request) +{ + HttpResponse response; + response.add_header("Server", "cfws"); + + std::stringstream sstream; + + FILE* fp = popen(executable_path.c_str(), "r"); + if (!fp) { + perror("cfws: popen"); + response.set_status_code(HttpStatusCode::InternalServerError); + response.add_header("Content-Type", "text/plain"); + response.set_content("Failed to open CGI executable!"); + return response; + } + + char ch; + while ((ch = fgetc(fp)) != EOF) + sstream << ch; + + pclose(fp); + + // TODO: We should be able to construct a repsonse from an entire string + // instead of always needing to individually set headers and content. + response.set_status_code(HttpStatusCode::OK); + response.add_header("Content-Type", "text/plain"); + response.set_content(sstream.str()); + return response; +} + static option long_options[] = { + { "cgi", required_argument, NULL, 'c' }, { "port", required_argument, NULL, 'p' }, }; int main(int argc, char** argv) { int port = 8080; - namespace fs = std::filesystem; + bool in_cgi_mode = false; + std::string cgi_program_name; int c; int option_index = 0; - while ((c = getopt_long(argc, argv, "p:", long_options, &option_index)) != -1) { + while ((c = getopt_long(argc, argv, "c:p:", long_options, &option_index)) != -1) { switch (c) { + case 'c': + in_cgi_mode = true; + cgi_program_name = optarg; + break; case 'p': port = atoi(optarg); if (port == 0) { @@ -35,44 +111,17 @@ int main(int argc, char** argv) } ServerConnection server(port); - std::cout << "cfws v0.1.0]\n"; + std::cout << "Serving a " << (in_cgi_mode ? "CGI exectuable" : "directory") << " on port " << port << std::endl; while (true) { - std::cout << "Waiting for connections on port " << port << std::endl; ClientConnection client = server.accept_client_connection(); HttpRequest request = client.read_request(); - - // Remove leading slash from the path if it exists - std::string relative_request_path = request.uri(); - while (*relative_request_path.begin() == '/') - relative_request_path.erase(0, 1); - - fs::path request_path = fs::current_path() / relative_request_path; - - // Look for an index.html if the requested path is a directory - if (fs::is_directory(request_path)) { - request_path /= "index.html"; - } - HttpResponse response; - response.add_header("Server", "cfws"); - - if (fs::exists(request_path)) { - std::string file_path = request_path.string(); - std::ifstream input_file(file_path); - if (!input_file.is_open()) { - std::cerr << "Failed to open file " << file_path << std::endl; - } - - std::string file_contents((std::istreambuf_iterator<char>(input_file)), std::istreambuf_iterator<char>()); - response.set_status_code(HttpStatusCode::OK); - response.add_header("Content-Type", "text/plain"); - response.set_content(file_contents); + if (in_cgi_mode) { + response = serve_from_cgi(cgi_program_name, request); } else { - response.set_status_code(HttpStatusCode::NotFound); - response.add_header("Content-Type", "text/plain"); - response.set_content("Page not found!"); + response = serve_from_filesystem(request); } client.send(response); |