diff options
| -rw-r--r-- | makefile | 2 | ||||
| -rw-r--r-- | server.cpp | 99 |
2 files changed, 83 insertions, 18 deletions
| @@ -1,4 +1,4 @@ | |||
| 1 | all: server | 1 | all: server |
| 2 | 2 | ||
| 3 | server: server.cpp | 3 | server: server.cpp |
| 4 | c++ -Wall -std=c++20 -pedantic -O2 -lfcgi -o $@ $< | 4 | c++ -Wall -std=c++20 -pedantic -O2 -o $@ $< -lfcgi |
| @@ -1,8 +1,15 @@ | |||
| 1 | // Standard C++ | 1 | // Standard C++ |
| 2 | #include <atomic> | 2 | #include <atomic> |
| 3 | #include <cerrno> | ||
| 3 | #include <csignal> | 4 | #include <csignal> |
| 4 | #include <cstdlib> | 5 | #include <cstdlib> |
| 6 | #include <cstring> | ||
| 7 | #include <exception> | ||
| 5 | #include <iostream> | 8 | #include <iostream> |
| 9 | #include <sstream> | ||
| 10 | #include <string> | ||
| 11 | #include <string_view> | ||
| 12 | #include <utility> | ||
| 6 | 13 | ||
| 7 | // FastCGI | 14 | // FastCGI |
| 8 | #include <fcgiapp.h> | 15 | #include <fcgiapp.h> |
| @@ -10,10 +17,14 @@ | |||
| 10 | using namespace std; | 17 | using namespace std; |
| 11 | 18 | ||
| 12 | namespace { | 19 | namespace { |
| 13 | static atomic_bool quit; | 20 | struct Configuration { |
| 14 | static atomic_bool reload; | 21 | int value; |
| 22 | }; | ||
| 15 | 23 | ||
| 16 | static void | 24 | atomic_bool quit{ false }; |
| 25 | atomic_bool reload{ false }; | ||
| 26 | |||
| 27 | void | ||
| 17 | handler(int signal) | 28 | handler(int signal) |
| 18 | { | 29 | { |
| 19 | if ( signal == SIGINT || signal == SIGTERM ) { | 30 | if ( signal == SIGINT || signal == SIGTERM ) { |
| @@ -24,7 +35,7 @@ handler(int signal) | |||
| 24 | } | 35 | } |
| 25 | } | 36 | } |
| 26 | 37 | ||
| 27 | static void | 38 | void |
| 28 | init_signal_handler() | 39 | init_signal_handler() |
| 29 | { | 40 | { |
| 30 | struct sigaction sa; | 41 | struct sigaction sa; |
| @@ -36,19 +47,48 @@ init_signal_handler() | |||
| 36 | sigaction(SIGINT, &sa, NULL); | 47 | sigaction(SIGINT, &sa, NULL); |
| 37 | sigaction(SIGTERM, &sa, NULL); | 48 | sigaction(SIGTERM, &sa, NULL); |
| 38 | sigaction(SIGHUP, &sa, NULL); | 49 | sigaction(SIGHUP, &sa, NULL); |
| 50 | |||
| 51 | signal(SIGPIPE, SIG_IGN); | ||
| 39 | } | 52 | } |
| 40 | 53 | ||
| 41 | static void | 54 | bool |
| 42 | load_configuration() | 55 | load_configuration(Configuration& configuration) |
| 43 | { | 56 | { |
| 44 | cerr << "Load configuration ...\n"; | 57 | cerr << "Load configuration ...\n"; |
| 58 | configuration.value = 1; | ||
| 59 | return true; | ||
| 60 | } | ||
| 61 | |||
| 62 | void | ||
| 63 | handle_request(char** env, const Configuration&, string_view body, ostream& out) | ||
| 64 | { | ||
| 65 | const char* methode = FCGX_GetParam("REQUEST_METHOD", env); | ||
| 66 | |||
| 67 | out << "Content-Type: text/html; charset=utf-8\r\n\r\n"; | ||
| 68 | out << "<h1>Verbindung erfolgreich verarbeitet!</h1>"; | ||
| 69 | out << "<p>Methode: " << (methode ? methode : "?") << ", Body: " << body.size() << " Bytes</p>"; | ||
| 45 | } | 70 | } |
| 46 | 71 | ||
| 47 | static void | 72 | void |
| 48 | handle_request(const FCGX_Request& request) | 73 | send_internal_error(const FCGX_Request& request) |
| 49 | { | 74 | { |
| 50 | FCGX_FPrintF(request.out, "Content-type: text/html\r\n\r\n"); | 75 | FCGX_FPrintF(request.out, "Status: 500 Internal Server Error\r\n"); |
| 51 | FCGX_FPrintF(request.out, "<h1>Verbindung erfolgreich verarbeitet!</h1>"); | 76 | FCGX_FPrintF(request.out, "Content-Type: text/plain; charset=utf-8\r\n\r\n"); |
| 77 | FCGX_FPrintF(request.out, "Die Anfrage konnte nicht verarbeitet werden.\n"); | ||
| 78 | } | ||
| 79 | |||
| 80 | string | ||
| 81 | read_request_body(const FCGX_Request& request) | ||
| 82 | { | ||
| 83 | string body; | ||
| 84 | char buffer[8192]; | ||
| 85 | int gelesen; | ||
| 86 | |||
| 87 | while ( (gelesen = FCGX_GetStr(buffer, sizeof buffer, request.in)) > 0 ) { | ||
| 88 | body.append(buffer, gelesen); | ||
| 89 | } | ||
| 90 | |||
| 91 | return body; | ||
| 52 | } | 92 | } |
| 53 | } // namespace | 93 | } // namespace |
| 54 | 94 | ||
| @@ -70,26 +110,51 @@ main() | |||
| 70 | } | 110 | } |
| 71 | 111 | ||
| 72 | init_signal_handler(); | 112 | init_signal_handler(); |
| 73 | load_configuration(); | ||
| 74 | 113 | ||
| 75 | quit = false; | 114 | Configuration configuration{}; |
| 76 | reload = false; | 115 | if ( !load_configuration(configuration) ) { |
| 116 | cerr << "Die Konfiguration konnte nicht geladen werden.\n"; | ||
| 117 | return EXIT_FAILURE; | ||
| 118 | } | ||
| 77 | 119 | ||
| 78 | cout << "Handle Requests...\n"; | 120 | cout << "Handle Requests...\n"; |
| 79 | 121 | ||
| 80 | while ( !quit ) { | 122 | while ( !quit ) { |
| 81 | if ( reload ) { | 123 | if ( reload.exchange(false) ) { |
| 82 | load_configuration(); | 124 | Configuration new_configuration{}; |
| 83 | reload = false; | 125 | |
| 126 | if ( load_configuration(new_configuration) ) { | ||
| 127 | configuration = std::move(new_configuration); | ||
| 128 | } | ||
| 129 | else { | ||
| 130 | cerr << "Neue Konfiguration nicht lesbar, die bisherige bleibt in Kraft.\n"; | ||
| 131 | } | ||
| 84 | } | 132 | } |
| 85 | 133 | ||
| 86 | if ( FCGX_Accept_r(&request) < 0 ) { | 134 | if ( FCGX_Accept_r(&request) < 0 ) { |
| 135 | if ( errno != EINTR ) { | ||
| 136 | cerr << "Fehler beim Annehmen der Verbindung: " << strerror(errno) << '\n'; | ||
| 137 | break; | ||
| 138 | } | ||
| 87 | continue; | 139 | continue; |
| 88 | } | 140 | } |
| 89 | 141 | ||
| 90 | handle_request(request); | 142 | try { |
| 143 | const string body = read_request_body(request); | ||
| 144 | |||
| 145 | ostringstream response; | ||
| 146 | handle_request(request.envp, configuration, body, response); | ||
| 147 | |||
| 148 | const string_view text = response.view(); | ||
| 149 | FCGX_PutStr(text.data(), static_cast<int>(text.size()), request.out); | ||
| 150 | } | ||
| 151 | catch ( const exception& e ) { | ||
| 152 | FCGX_FPrintF(request.err, "Fehler beim Verarbeiten der Anfrage: %s\n", e.what()); | ||
| 153 | send_internal_error(request); | ||
| 154 | } | ||
| 91 | 155 | ||
| 92 | FCGX_Finish_r(&request); | 156 | FCGX_Finish_r(&request); |
| 93 | } | 157 | } |
| 158 | |||
| 94 | cout << "shutdown...\n"; | 159 | cout << "shutdown...\n"; |
| 95 | } | 160 | } |
