diff options
Diffstat (limited to 'click-fcgi.cpp')
-rw-r--r-- | click-fcgi.cpp | 129 |
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; +} + |