summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRoland Reichwein <mail@reichwein.it>2023-01-13 17:40:09 +0100
committerRoland Reichwein <mail@reichwein.it>2023-01-13 17:40:09 +0100
commitc0d9d61e3330d4f69a9547cc3d0e62970fb7427e (patch)
treeffc906ba3ddbe97dbf1042b14063caa7debe141d
parentd14582a1d92e036780166a0b5ec0494d7353cc75 (diff)
Added webapp-runner
-rw-r--r--TODO1
-rw-r--r--debian/changelog1
-rw-r--r--debian/webserver.manpages1
-rw-r--r--plugins/fcgi/Makefile8
-rw-r--r--plugins/fcgi/fastcgiprocess.cpp84
-rw-r--r--plugins/fcgi/fastcgiprocess.h3
-rw-r--r--plugins/fcgi/webapp-runner.cpp54
-rw-r--r--tests/webserverprocess.cpp2
-rw-r--r--webapp-runner.123
9 files changed, 138 insertions, 39 deletions
diff --git a/TODO b/TODO
index 5cc50fd..2e7a58a 100644
--- a/TODO
+++ b/TODO
@@ -3,7 +3,6 @@ example conf files:
Big file bug
- dynamic plugin interface (file buffer, ...)
-FastCGI from command line
stats.png
cgi unhandled headers
git via smart http / cgi
diff --git a/debian/changelog b/debian/changelog
index 3f3b762..43a487f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -5,6 +5,7 @@ webserver (1.18~pre1) UNRELEASED; urgency=medium
* Added example configurations
* FCGI bugfix: IPv6 support
* FCGI: Implemented direct application start
+ * Added webapp-runner for FCGI applications (replacement for spawn-fcgi)
-- Roland Reichwein <mail@reichwein.it> Sun, 08 Jan 2023 15:26:48 +0100
diff --git a/debian/webserver.manpages b/debian/webserver.manpages
index 0bf93db..9d38ea1 100644
--- a/debian/webserver.manpages
+++ b/debian/webserver.manpages
@@ -1 +1,2 @@
webserver.1
+webapp-runner.1
diff --git a/plugins/fcgi/Makefile b/plugins/fcgi/Makefile
index e878c5d..81502c4 100644
--- a/plugins/fcgi/Makefile
+++ b/plugins/fcgi/Makefile
@@ -27,11 +27,14 @@ PROGSRC=\
SRC=$(PROGSRC)
-all: $(PROJECTNAME).so
+all: $(PROJECTNAME).so webapp-runner
$(PROJECTNAME).so: $(SRC:.cpp=.o)
$(CXX) $(CXXFLAGS) $^ -shared $(LIBS) -o $@
+webapp-runner: webapp-runner.o fastcgiprocess.o
+ $(CXX) $(LDFLAGS) $^ $(LDLIBS) $(LIBS) -o $@
+
%.d: %.cpp
$(CXX) $(CXXFLAGS) -MM -MP -MF $@ -c $<
@@ -45,13 +48,14 @@ ADD_DEP=Makefile
install:
mkdir -p $(DESTDIR)/usr/lib/webserver/plugins
cp $(PROJECTNAME).so $(DESTDIR)/usr/lib/webserver/plugins
+ cp webapp-runner $(DESTDIR)/usr/bin
# misc ---------------------------------------------------
debs: $(DISTROS)
clean:
- -rm -f *.o *.so *.d
+ -rm -f *.o *.so *.d webapp-runner
.PHONY: clean install all
diff --git a/plugins/fcgi/fastcgiprocess.cpp b/plugins/fcgi/fastcgiprocess.cpp
index dd51583..d43fa75 100644
--- a/plugins/fcgi/fastcgiprocess.cpp
+++ b/plugins/fcgi/fastcgiprocess.cpp
@@ -61,6 +61,51 @@ FastCGIProcess::~FastCGIProcess()
stop();
}
+void run_fcgi_app(const std::string& command, const std::string& host, unsigned short port)
+{
+ boost::asio::io_context ioc;
+ boost::asio::ip::tcp::resolver resolver(ioc);
+ boost::asio::ip::tcp::acceptor acceptor(ioc);
+ auto const results = resolver.resolve(host.c_str(), std::to_string(port).c_str());
+ if (results.begin() == results.end())
+ std::runtime_error("no resolve result");
+ boost::asio::ip::tcp::endpoint endpoint{*results.begin()};
+ acceptor.open(endpoint.protocol());
+ acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
+ acceptor.bind(endpoint);
+ acceptor.listen();
+ int fd{acceptor.native_handle()};
+ if (fd != FCGI_LISTENSOCK_FILENO) {
+ close(FCGI_LISTENSOCK_FILENO);
+ dup2(fd, FCGI_LISTENSOCK_FILENO);
+ close(fd);
+ }
+
+ execl(command.c_str(), command.c_str(), (const char*)nullptr);
+}
+
+void run_fcgi_app(const std::string& command, const std::filesystem::path& socket_path)
+{
+ boost::asio::io_context ioc;
+ boost::asio::local::stream_protocol::acceptor file_acceptor(ioc);
+ std::error_code ec;
+ fs::remove(socket_path, ec); // otherwise we get: "bind: Address already in use"
+
+ boost::asio::local::stream_protocol::endpoint endpoint(socket_path);
+ file_acceptor.open(endpoint.protocol());
+ file_acceptor.set_option(boost::asio::local::stream_protocol::acceptor::reuse_address(true));
+ file_acceptor.bind(endpoint);
+ file_acceptor.listen();
+ int fd {file_acceptor.native_handle()};
+ if (fd != FCGI_LISTENSOCK_FILENO) {
+ close(FCGI_LISTENSOCK_FILENO);
+ dup2(fd, FCGI_LISTENSOCK_FILENO);
+ close(fd);
+ }
+
+ execl(command.c_str(), command.c_str(), (const char*)nullptr);
+}
+
void FastCGIProcess::start()
{
if (m_pid != 0)
@@ -72,41 +117,10 @@ void FastCGIProcess::start()
if (m_pid == 0) { // child process branch
try {
- int fd{};
- boost::asio::io_context ioc;
- boost::asio::ip::tcp::resolver resolver(ioc);
- boost::asio::ip::tcp::acceptor acceptor(ioc);
- boost::asio::local::stream_protocol::acceptor file_acceptor(ioc);
-
- if (m_socket_path.empty()) { // tcp connection
- auto const results = resolver.resolve(m_host.c_str(), std::to_string(m_port).c_str());
- if (results.begin() == results.end())
- std::runtime_error("no resolve result");
- boost::asio::ip::tcp::endpoint endpoint{*results.begin()};
- acceptor.open(endpoint.protocol());
- acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
- acceptor.bind(endpoint);
- acceptor.listen();
- fd = acceptor.native_handle();
- } else { // unix domain socket
- std::error_code ec;
- fs::remove(m_socket_path, ec); // otherwise we get: "bind: Address already in use"
-
- boost::asio::local::stream_protocol::endpoint endpoint(m_socket_path);
- file_acceptor.open(endpoint.protocol());
- file_acceptor.set_option(boost::asio::local::stream_protocol::acceptor::reuse_address(true));
- file_acceptor.bind(endpoint);
- file_acceptor.listen();
- fd = file_acceptor.native_handle();
- }
-
- if (fd != FCGI_LISTENSOCK_FILENO) {
- close(FCGI_LISTENSOCK_FILENO);
- dup2(fd, FCGI_LISTENSOCK_FILENO);
- close(fd);
- }
-
- execl(m_command.c_str(), m_command.c_str(), (const char*)nullptr);
+ if (m_socket_path.empty())
+ run_fcgi_app(m_command, m_host, m_port);
+ else
+ run_fcgi_app(m_command, m_socket_path);
} catch (const std::exception& ex) {
std::cout << "FastCGI process error: " << ex.what() << std::endl;
}
diff --git a/plugins/fcgi/fastcgiprocess.h b/plugins/fcgi/fastcgiprocess.h
index 07b6539..18a5d5b 100644
--- a/plugins/fcgi/fastcgiprocess.h
+++ b/plugins/fcgi/fastcgiprocess.h
@@ -10,6 +10,9 @@
#include <sys/mman.h>
#include <sys/types.h>
+void run_fcgi_app(const std::string& command, const std::string& host, unsigned short port);
+void run_fcgi_app(const std::string& command, const std::filesystem::path& socket_path);
+
class FastCGIProcess
{
public:
diff --git a/plugins/fcgi/webapp-runner.cpp b/plugins/fcgi/webapp-runner.cpp
new file mode 100644
index 0000000..64268f3
--- /dev/null
+++ b/plugins/fcgi/webapp-runner.cpp
@@ -0,0 +1,54 @@
+#include "plugins/fcgi/fastcgiprocess.h"
+
+#include <iostream>
+#include <string>
+
+namespace {
+ void usage()
+ {
+ std::cout << R"(Usage:
+ webapp-runner <host:port> <executable-command>
+
+ or:
+
+ webapp-runner <unix-domain-socket> <executable-command>
+
+Description:
+
+webapp-runner starts the specified executable FastCGI application and connects
+it to the specified unix domain socket or local host:port address. Addresses
+can be specified in IPv4 or IPv6 format.
+
+Examples:
+
+webapp-runner ::1:6543 ./fcgi1
+webapp-runner fcgi-socket0 ./fcgi1
+)" << std::endl;
+ }
+} // namespace
+
+int main(int argc, char* argv[])
+{
+ try {
+ if (argc == 3) {
+ std::string address{argv[1]};
+ std::string command{argv[2]};
+
+ if (auto pos{address.find_last_of(':')}; pos != std::string::npos) {
+ std::string host{address.substr(0, pos)};
+ unsigned short port{static_cast<unsigned short>(std::stoul(address.substr(pos + 1)))};
+ run_fcgi_app(command, host, port);
+ } else {
+ run_fcgi_app(command, address);
+ }
+ } else {
+ usage();
+ exit(0);
+ }
+ } catch (const std::exception& ex) {
+ std::cout << "webapp-runner caught error: " << ex.what() << std::endl;
+ }
+
+ return 0;
+}
+
diff --git a/tests/webserverprocess.cpp b/tests/webserverprocess.cpp
index edafaaa..f9ecdd3 100644
--- a/tests/webserverprocess.cpp
+++ b/tests/webserverprocess.cpp
@@ -194,7 +194,7 @@ void WebserverProcess::start()
// wait for server to start up
if (int port{port_from_config(m_config)}; port >= 0)
Process::wait_for_pid_listening_on(m_pid, port);
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
void WebserverProcess::stop()
diff --git a/webapp-runner.1 b/webapp-runner.1
new file mode 100644
index 0000000..724cff5
--- /dev/null
+++ b/webapp-runner.1
@@ -0,0 +1,23 @@
+.TH webapp-runner 1 "12 Jan 2023" "Version 1.18" "Webserver Manual"
+
+.SH NAME
+webapp-runner \- A FastCGI application runner
+
+.SH SYNOPSIS
+webapp-runner <host:port> <executable-command>
+
+webapp-runner <unix-domain-socket> <executable-command>
+
+.SH DESCRIPTION
+.B webapp-runner
+starts the specified executable FastCGI application and connects
+it to the specified unix domain socket or local host:port address. Addresses
+can be specified in IPv4 or IPv6 format.
+
+.SH EXAMPLES
+webapp-runner ::1:6543 ./fcgi1
+
+webapp-runner fcgi-socket0 ./fcgi1
+
+.SH AUTHOR
+Roland Reichwein <mail@reichwein.it>