summaryrefslogtreecommitdiffhomepage
path: root/plugins/fcgi/fcgi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/fcgi/fcgi.cpp')
-rw-r--r--plugins/fcgi/fcgi.cpp207
1 files changed, 88 insertions, 119 deletions
diff --git a/plugins/fcgi/fcgi.cpp b/plugins/fcgi/fcgi.cpp
index 464ba75..4ff8253 100644
--- a/plugins/fcgi/fcgi.cpp
+++ b/plugins/fcgi/fcgi.cpp
@@ -1,6 +1,7 @@
#include "fcgi.h"
#include "fastcgi.h"
+#include "socket.h"
#include <boost/algorithm/string/predicate.hpp>
#include <boost/array.hpp>
@@ -343,149 +344,119 @@ std::string fcgi_plugin::fcgiQuery(FCGIContext& context)
std::unordered_map<std::string, std::string> app_values; // will be read by FCGI_GET_VALUES
- size_t pos { app_addr.find(':') };
- if (pos != app_addr.npos) { // tcp socket: host:port
- auto endpoints{m_resolver.resolve(app_addr.substr(0, pos), app_addr.substr(pos + 1))};
- bool opening{false};
-
- std::lock_guard<std::mutex> socket_lock{m_socket_mutex};
+ auto it {m_sockets.find(app_addr)};
- auto it {m_sockets.find(app_addr)};
+ std::shared_ptr<Socket> socket;
- std::pair<std::unordered_map<std::string, boost::asio::ip::tcp::socket>::iterator, bool> it2{m_sockets.end(), false};
- if (it == m_sockets.end())
- it2 = m_sockets.emplace(app_addr, m_io_context); // add new element if necessary
+ if (it == m_sockets.end()) { // add new element
+ socket = m_socket_factory.create(app_addr);
- boost::asio::ip::tcp::socket& socket { it2.second ? it2.first->second : it->second }; // use just added element or previously found one
+ if (!socket) {
+ std::cerr << "FCGI Error: Invalid app_addr." << std::endl;
+ return HttpStatus("500", "FCGI configuration", context.SetResponseHeader);
+ }
- socket.close(); // TODO: Bug workaround: Keeping TCP socket open doesn't work for now
+ m_sockets[app_addr] = socket;
- if (!socket.is_open()) {
- std::cout << "FCGI: Opening new socket" << std::endl;
+ } else { // use already existing element
+ socket = it->second;
+ }
- boost::asio::connect(socket, endpoints);
+ bool opening{false};
+
+ std::lock_guard<std::mutex> socket_lock{socket->getMutex()};
- boost::asio::socket_base::keep_alive keepAlive(true);
- socket.set_option(keepAlive);
+ socket->close(); // TODO: Bug workaround: Keeping TCP socket open doesn't work for now
- struct timeval tv;
- tv.tv_sec = 0; // infinite
- tv.tv_usec = 0;
- if (setsockopt(socket.native_handle(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)))
- std::cerr << "FCGI Error: SO_RCVTIMEO" << std::endl;
+ if (!socket->is_open()) {
+ std::cout << "FCGI: Opening new socket" << std::endl;
- if (setsockopt(socket.native_handle(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)))
- std::cerr << "FCGI Error: SO_SNDTIMEO" << std::endl;
+ socket->open();
+ opening = true;
+ }
- int val{1};
- if (setsockopt(socket.native_handle(), SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)))
- std::cerr << "FCGI Error: SO_KEEPALIVE" << std::endl;
+ if (!socket->is_open()) {
+ return HttpStatus("500", "FCGI connection", context.SetResponseHeader);
+ }
- opening = true;
- }
+ FCGI_ID_Guard id_guard(socket->fcgi_id());
+ uint16_t id {id_guard.getID()};
- if (!socket.is_open()) {
- return HttpStatus("500", "FCGI connection", context.SetResponseHeader);
+ try {
+ if (opening) {
+ FCGI_Record get_values{FCGI_GET_VALUES, 0, system_config_bytes};
+ if (socket->write(get_values.getBuffer()) != get_values.getBuffer().size())
+ std::cerr << "Warning: Not all bytes written 1" << std::endl;
}
- FCGI_ID_Guard id_guard(m_fcgi_id);
- uint16_t id {id_guard.getID()};
-
- try {
- if (opening) {
- FCGI_Record get_values{FCGI_GET_VALUES, 0, system_config_bytes};
- if (socket.write_some(boost::asio::buffer(get_values.getBuffer())) != get_values.getBuffer().size())
- std::cerr << "Warning: Not all bytes written 1" << std::endl;
- }
-
- FCGI_Record begin_request{FCGI_BEGIN_REQUEST, id, FCGI_RESPONDER, FCGI_KEEP_CONN};
- if (socket.write_some(boost::asio::buffer(begin_request.getBuffer())) != begin_request.getBuffer().size())
- std::cerr << "Warning: Not all bytes written 3" << std::endl;
+ FCGI_Record begin_request{FCGI_BEGIN_REQUEST, id, FCGI_RESPONDER, FCGI_KEEP_CONN};
+ if (socket->write(begin_request.getBuffer()) != begin_request.getBuffer().size())
+ std::cerr << "Warning: Not all bytes written 3" << std::endl;
- FCGI_Record params{FCGI_PARAMS, id, env_bytes};
- if (socket.write_some(boost::asio::buffer(params.getBuffer())) != params.getBuffer().size())
- std::cerr << "Warning: Not all bytes written 4" << std::endl;
+ FCGI_Record params{FCGI_PARAMS, id, env_bytes};
+ if (socket->write(params.getBuffer()) != params.getBuffer().size())
+ std::cerr << "Warning: Not all bytes written 4" << std::endl;
- if (env_bytes.size()) {
- FCGI_Record params_end{FCGI_PARAMS, id, std::string{}};
- if (socket.write_some(boost::asio::buffer(params_end.getBuffer())) != params_end.getBuffer().size())
- std::cerr << "Warning: Not all bytes written 5" << std::endl;
- }
+ if (env_bytes.size()) {
+ FCGI_Record params_end{FCGI_PARAMS, id, std::string{}};
+ if (socket->write(params_end.getBuffer()) != params_end.getBuffer().size())
+ std::cerr << "Warning: Not all bytes written 5" << std::endl;
+ }
- std::string body {context.GetRequestParam("body")};
- FCGI_Record stdin_{FCGI_STDIN, id, body};
- if (socket.write_some(boost::asio::buffer(stdin_.getBuffer())) != stdin_.getBuffer().size())
- std::cerr << "Warning: Not all bytes written 6" << std::endl;
-
- if (body.size()) {
- FCGI_Record stdin_end{FCGI_STDIN, id, std::string{}};
- if (socket.write_some(boost::asio::buffer(stdin_end.getBuffer())) != stdin_end.getBuffer().size())
- std::cerr << "Warning: Not all bytes written 7" << std::endl;
- }
- } catch (const boost::system::system_error& ex) {
- if (ex.code() == boost::asio::error::eof) {
- std::cerr << "FCGI Error: EOF on write" << std::endl; // seems to be ok here
- return HttpStatus("500", "FCGI connection: EOF on write", context.SetResponseHeader);
- }
+ std::string body {context.GetRequestParam("body")};
+ FCGI_Record stdin_{FCGI_STDIN, id, body};
+ if (socket->write(stdin_.getBuffer()) != stdin_.getBuffer().size())
+ std::cerr << "Warning: Not all bytes written 6" << std::endl;
+
+ if (body.size()) {
+ FCGI_Record stdin_end{FCGI_STDIN, id, std::string{}};
+ if (socket->write(stdin_end.getBuffer()) != stdin_end.getBuffer().size())
+ std::cerr << "Warning: Not all bytes written 7" << std::endl;
}
+ } catch (const fcgi_eof_error&) {
+ std::cerr << "FCGI Error: EOF on write" << std::endl; // seems to be ok here
+ return HttpStatus("500", "FCGI connection: EOF on write", context.SetResponseHeader);
+ }
#if 0
- FCGI_Record data{FCGI_DATA, id, std::string{}};
- if (socket.write_some(boost::asio::buffer(data.getBuffer())) != data.getBuffer().size())
- std::cerr << "Warning: Not all bytes written 8" << std::endl;
+ FCGI_Record data{FCGI_DATA, id, std::string{}};
+ if (socket->write(data.getBuffer()) != data.getBuffer().size())
+ std::cerr << "Warning: Not all bytes written 8" << std::endl;
#endif
- bool ended{false};
- std::vector<char> inbuf;
- std::vector<char> inbuf_part(1024);
- while (!ended) {
+ bool ended{false};
+ std::vector<char> inbuf;
+ std::vector<char> inbuf_part(1024);
+ while (!ended) {
+ try {
+ size_t got {socket->read(inbuf_part)};
+ inbuf.insert(inbuf.end(), inbuf_part.begin(), inbuf_part.begin() + got);
+ } catch (const fcgi_eof_error&) {
+ //std::cerr << "FCGI Warning: Early EOF" << std::endl; // seems to be ok here
+ ended = true;
+ //return HttpStatus("500", "FCGI connection: EOF on read", context.SetResponseHeader);
+ }
+
+ while (inbuf.size() > 0) {
+
try {
- size_t got {socket.read_some(boost::asio::buffer(inbuf_part))};
- inbuf.insert(inbuf.end(), inbuf_part.begin(), inbuf_part.begin() + got);
- } catch (const boost::system::system_error& ex) {
- if (ex.code() == boost::asio::error::eof) {
- //std::cerr << "FCGI Warning: Early EOF" << std::endl; // seems to be ok here
- ended = true;
- //return HttpStatus("500", "FCGI connection: EOF on read", context.SetResponseHeader);
- } else {
- std::cerr << "FCGI Warning: Expected EOF, got " << ex.code() << ", " << ex.what() << std::endl;
+ FCGI_Record r{inbuf};
+ if (r.getType() == FCGI_END_REQUEST) {
ended = true;
- }
- }
-
- while (inbuf.size() > 0) {
-
- try {
- FCGI_Record r{inbuf};
- if (r.getType() == FCGI_END_REQUEST) {
- ended = true;
- } else if (r.getType() == FCGI_STDOUT) {
- output_data += r.getContent();
- } else if (r.getType() == FCGI_STDERR) {
- std::cerr << "FCGI STDERR: " << r.getContent() << std::endl;
- } else if (r.getType() == FCGI_GET_VALUES_RESULT) {
- FCGI_DecodeEnv(r.getContent(), app_values);
- DumpAppValues(app_values);
- } else
- throw std::runtime_error("Unhandled FCGI type: "s + std::to_string(r.getType()));
- } catch (const std::length_error& ex) {
- // ignore if not enough data available yet
- break;
- }
+ } else if (r.getType() == FCGI_STDOUT) {
+ output_data += r.getContent();
+ } else if (r.getType() == FCGI_STDERR) {
+ std::cerr << "FCGI STDERR: " << r.getContent() << std::endl;
+ } else if (r.getType() == FCGI_GET_VALUES_RESULT) {
+ FCGI_DecodeEnv(r.getContent(), app_values);
+ DumpAppValues(app_values);
+ } else
+ throw std::runtime_error("Unhandled FCGI type: "s + std::to_string(r.getType()));
+ } catch (const std::length_error& ex) {
+ // ignore if not enough data available yet
+ break;
}
}
-
- } else if (fs::is_socket(fs::path{app_addr})) { // Unix domain socket
- // TODO
- std::cerr << "FCGI Error: Unix domain sockets not yet implemented." << std::endl;
- return HttpStatus("500", "FCGI configuration", context.SetResponseHeader);
- } else if (fs::is_regular_file(fs::path{app_addr})) { // Executable to start
- // TODO
- std::cerr << "FCGI Error: Executable FCGI not yet implemented." << std::endl;
- return HttpStatus("500", "FCGI configuration", context.SetResponseHeader);
- } else {
- std::cerr << "FCGI Error: Invalid app_addr type." << std::endl;
- return HttpStatus("500", "FCGI configuration", context.SetResponseHeader);
}
std::istringstream is_out{output_data};
@@ -532,8 +503,6 @@ std::string fcgi_plugin::name()
}
fcgi_plugin::fcgi_plugin()
- : m_io_context()
- , m_resolver(m_io_context)
{
//std::cout << "Plugin constructor" << std::endl;
}