summaryrefslogtreecommitdiffhomepage
path: root/click-fcgi.cpp
diff options
context:
space:
mode:
authorRoland Reichwein <mail@reichwein.it>2025-01-20 21:56:53 +0100
committerRoland Reichwein <mail@reichwein.it>2025-01-20 21:56:53 +0100
commit2c5684482c14764cec4fb32b2ec07dd3f77fd4bf (patch)
tree9ff9c5c04a20c30568f4ce1c466fe55818a0b45b /click-fcgi.cpp
parent5fd637644c7529bfdc5291215f3f8ee1edd304c4 (diff)
Add click-fcgi (WIP)HEADmaster
Diffstat (limited to 'click-fcgi.cpp')
-rw-r--r--click-fcgi.cpp129
1 files changed, 129 insertions, 0 deletions
diff --git a/click-fcgi.cpp b/click-fcgi.cpp
new file mode 100644
index 0000000..8b422ca
--- /dev/null
+++ b/click-fcgi.cpp
@@ -0,0 +1,129 @@
+#include "config.h"
+
+#include <stdexcept>
+#include <string>
+#include <iostream>
+
+#include <fcgiapp.h>
+
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+#include <fmt/format.h>
+
+namespace pt = boost::property_tree;
+
+using namespace std::string_literals;
+
+namespace {
+
+class PostData
+{
+public:
+ PostData(FCGX_Request& request) {
+ std::string result;
+ std::string contentLengthString(FCGX_GetParam("CONTENT_LENGTH", request.envp));
+ int contentLength = std::stoul(contentLengthString);
+
+ result.resize(contentLength);
+
+ unsigned int status = FCGX_GetStr(result.data(), result.size(), request.in);
+ if (status != result.size()) {
+ throw std::runtime_error(fmt::format("Read error: {}/{}", status, result.size()));
+ }
+
+ m_data = result;
+ }
+
+ std::string getData()
+ {
+ return m_data;
+ }
+
+ // path: xml path, e.g. data.value
+ std::string getXMLElement(const std::string& path)
+ {
+ pt::ptree tree{};
+ std::istringstream iss{m_data};
+ pt::read_xml(iss, tree, pt::xml_parser::trim_whitespace);
+
+ return tree.get<std::string>(path);
+ }
+
+private:
+ std::string m_data;
+};
+
+std::string getCommand(FCGX_Request& request)
+{
+ std::string query = FCGX_GetParam("QUERY_STRING", request.envp);
+ size_t pos = query.find("command=");
+ if (pos != query.npos) {
+ return query.substr(pos + 8);
+ } else {
+ return {};
+ }
+}
+
+std::string to_xml()
+{
+ std::string result{"<data><status>ok</status><ui>"};
+
+ result += "ui1</ui>";
+ return result + "</data>";
+}
+
+} // namespace
+
+int main(int argc, char* argv[]) {
+ try {
+ Config config{argc, argv};
+
+ std::string ok_data{"<data><status>ok</status><message>OK</message></data>"};
+ std::string error_data{"<data><status>error</status><message>General Error</message></data>"};
+
+ int result = FCGX_Init();
+ if (result != 0) {
+ return 1; // error on init
+ }
+
+ FCGX_Request request;
+
+ if (FCGX_InitRequest(&request, 0, 0) != 0) {
+ return 1; // error on init
+ }
+
+ while (FCGX_Accept_r(&request) == 0) {
+ std::string method = FCGX_GetParam("REQUEST_METHOD", request.envp);
+
+ FCGX_PutS("Content-Type: text/xml\r\n\r\n", request.out);
+
+ try {
+ if (method == "POST") {
+ PostData data{request};
+ std::string command {getCommand(request)};
+ if (command == "start") {
+ FCGX_PutS(ok_data.c_str(), request.out);
+ } else if (command == "stop") {
+ FCGX_PutS(ok_data.c_str(), request.out);
+ } else if (command == "getui") {
+ FCGX_PutS(to_xml().c_str(), request.out);
+ } else if (command == "setfile") {
+ std::string filename = data.getXMLElement("data.value");
+ FCGX_PutS(ok_data.c_str(), request.out);
+ } else {
+ FCGX_PutS(error_data.c_str(), request.out);
+ }
+ } else {
+ throw std::runtime_error(fmt::format("Bad request method: POST expected, got {}", method).c_str());
+ }
+ } catch (const std::exception& ex) {
+ FCGX_PutS(("<data><status>error</status><message>Error: "s + ex.what() + "</message></data>").c_str(), request.out);
+ }
+ }
+ } catch (const std::exception& ex) {
+ std::cerr << "Error: " << ex.what() << std::endl;
+ }
+
+ return 0;
+}
+