diff options
| author | Roland Reichwein <mail@reichwein.it> | 2020-04-26 13:01:19 +0200 | 
|---|---|---|
| committer | Roland Reichwein <mail@reichwein.it> | 2020-04-26 13:01:19 +0200 | 
| commit | aebe139d00b44684158edb3616da5c37b12db6d1 (patch) | |
| tree | f37eaa7a59523f2e7db42875e65f2ca2714c0e9d /plugins/statistics | |
| parent | 91073ca08f5f9582196712ae6753714f3333979f (diff) | |
Added stats output
Diffstat (limited to 'plugins/statistics')
| -rw-r--r-- | plugins/statistics/Makefile | 124 | ||||
| -rw-r--r-- | plugins/statistics/statistics.cpp | 97 | ||||
| -rw-r--r-- | plugins/statistics/statistics.h | 21 | 
3 files changed, 242 insertions, 0 deletions
diff --git a/plugins/statistics/Makefile b/plugins/statistics/Makefile new file mode 100644 index 0000000..48c2e8c --- /dev/null +++ b/plugins/statistics/Makefile @@ -0,0 +1,124 @@ +DISTROS=debian10 +VERSION=$(shell dpkg-parsechangelog --show-field Version) +PROJECTNAME=statistics + +CXX=clang++-10 + +ifeq ($(shell which $(CXX)),) +CXX=clang++ +endif + +ifeq ($(shell which $(CXX)),) +CXX=g++-9 +endif + +ifeq ($(CXXFLAGS),) +#CXXFLAGS=-O2 -DNDEBUG +CXXFLAGS=-O0 -g -D_DEBUG +endif +# -fprofile-instr-generate -fcoverage-mapping +# gcc:--coverage + +CXXFLAGS+= -Wall -I. + +CXXFLAGS+= -pthread -fvisibility=hidden -fPIC +ifeq ($(CXX),clang++-10) +CXXFLAGS+=-std=c++20 #-stdlib=libc++ +else +CXXFLAGS+=-std=c++17 +endif + +CXXTESTFLAGS=-Igoogletest/include -Igooglemock/include/ -Igoogletest -Igooglemock + +LIBS=\ +-lboost_context \ +-lboost_coroutine \ +-lboost_program_options \ +-lboost_system \ +-lboost_thread \ +-lboost_filesystem \ +-lboost_regex \ +-lpthread \ +-lssl -lcrypto \ +-ldl + +ifeq ($(CXX),clang++-10) +LIBS+= \ +-fuse-ld=lld-10 \ +-lstdc++ +#-lc++ \ +#-lc++abi +#-lc++fs +#-lstdc++fs +else +LIBS+= \ +-lstdc++ \ +-lstdc++fs +endif + +PROGSRC=\ +    statistics.cpp + +TESTSRC=\ +    test-webserver.cpp \ +    googlemock/src/gmock-all.cpp \ +    googletest/src/gtest-all.cpp \ +    $(PROGSRC) + +SRC=$(PROGSRC) + +all: $(PROJECTNAME).so + +# testsuite ---------------------------------------------- +test-$(PROJECTNAME): $(TESTSRC:.cpp=.o) +	$(CXX) $(CXXFLAGS) $^ $(LIBS) -o $@ + +$(PROJECTNAME).so: $(SRC:.cpp=.o) +	$(CXX) -shared $(CXXFLAGS) $^ $(LIBS) -o $@ + +dep: $(TESTSRC:.cpp=.d) + +%.d: %.cpp +	$(CXX) $(CXXFLAGS) $(CXXTESTFLAGS) -MM -MP -MF $@ -c $< + +%.o: %.cpp %.d +	$(CXX) $(CXXFLAGS) $(CXXTESTFLAGS) -c $< -o $@ + +googletest/src/%.o: googletest/src/%.cc +	$(CXX) $(CXXFLAGS) $(CXXTESTFLAGS) -c $< -o $@ + +# dependencies + +ADD_DEP=Makefile + +install: +	mkdir -p $(DESTDIR)/usr/lib/webserver/plugins +	cp $(PROJECTNAME).so $(DESTDIR)/usr/lib/webserver/plugins + +# misc --------------------------------------------------- +deb: +	# build binary deb package +	dpkg-buildpackage -us -uc -rfakeroot + +deb-src: +	dpkg-source -b . + +$(DISTROS): deb-src +	sudo pbuilder build --basetgz /var/cache/pbuilder/$@.tgz --buildresult result/$@ ../webserver_$(VERSION).dsc ; \ + +debs: $(DISTROS) + +clean: +	-rm -f test-$(PROJECTNAME) $(PROJECTNAME) +	-find . -name '*.o' -o -name '*.so' -o -name '*.d' -o -name '*.gcno' -o -name '*.gcda' | xargs rm -f + +zip: clean +	-rm -f ../$(PROJECTNAME).zip +	zip -r ../$(PROJECTNAME).zip * +	ls -l ../$(PROJECTNAME).zip + + + +.PHONY: clean all zip install deb deb-src debs all $(DISTROS) + +-include $(wildcard $(SRC:.cpp=.d)) diff --git a/plugins/statistics/statistics.cpp b/plugins/statistics/statistics.cpp new file mode 100644 index 0000000..03f4c94 --- /dev/null +++ b/plugins/statistics/statistics.cpp @@ -0,0 +1,97 @@ +#include "statistics.h" + +#include <boost/algorithm/string/predicate.hpp> +#include <boost/coroutine2/coroutine.hpp> +#include <boost/process.hpp> + +#include <algorithm> +#include <filesystem> +#include <fstream> +#include <iostream> +#include <string> +#include <unordered_map> + +using namespace std::string_literals; +namespace bp = boost::process; +namespace fs = std::filesystem; + +namespace { + + // Used to return errors by generating response page and HTTP status code + std::string HttpStatus(std::string status, std::string message, std::function<plugin_interface_setter_type>& SetResponseHeader) + { +  SetResponseHeader("status", status); +  SetResponseHeader("content_type", "text/html"); +  return status + " " + message; + } + +} // anonymous namespace + +std::string statistics_plugin::name() +{ + return "statistics"; +} + +statistics_plugin::statistics_plugin() +{ + //std::cout << "Plugin constructor" << std::endl; +} + +statistics_plugin::~statistics_plugin() +{ + //std::cout << "Plugin destructor" << std::endl; +} + +std::string statistics_plugin::generate_page( +  std::function<std::string(const std::string& key)>& GetServerParam, +  std::function<std::string(const std::string& key)>& GetRequestParam, // request including body (POST...) +  std::function<void(const std::string& key, const std::string& value)>& SetResponseHeader // to be added to result string +) +{ + try { +  // Request path must not contain "..". +  std::string rel_target{GetRequestParam("rel_target")}; +  size_t query_pos{rel_target.find("?")}; +  if (query_pos != rel_target.npos) +   rel_target = rel_target.substr(0, query_pos); + +  std::string target{GetRequestParam("target")}; +  if (rel_target.find("..") != std::string::npos) { +   return HttpStatus("400", "Illegal request: "s + target, SetResponseHeader); +  } + +  // Build the path to the requested file +  std::string doc_root{GetRequestParam("doc_root")}; +  fs::path path {fs::path{doc_root} / rel_target}; +  if (target.size() && target.back() != '/' && fs::is_directory(path)) { +   std::string location{GetRequestParam("location") + "/"s}; +   SetResponseHeader("location", location); +   return HttpStatus("301", "Correcting directory path", SetResponseHeader); +  } + +  try { +   SetResponseHeader("content_type", "text/html"); + +   std::string header {"<!DOCTYPE html><html><head>" +             "<meta charset=\"utf-8\"/>" +             "<title>Webserver Statistics</title>" +             "</head><body>"}; +   std::string footer{"<br/><br/><br/></body></html>"}; + +   std::string result{header}; + +   result += "<h1>Webserver Statistics</h1>"; +   result += "<pre>"s + GetServerParam("statistics") + "</pre>"s; + +   result += footer; +    +   return result; +  } catch (const std::exception& ex) { +   return HttpStatus("500", "Statistics error: "s + ex.what(), SetResponseHeader); +  } + + } catch (const std::exception& ex) { +  return HttpStatus("500", "Unknown Error: "s + ex.what(), SetResponseHeader); + } +} + diff --git a/plugins/statistics/statistics.h b/plugins/statistics/statistics.h new file mode 100644 index 0000000..5db309b --- /dev/null +++ b/plugins/statistics/statistics.h @@ -0,0 +1,21 @@ +#pragma once + +#include "../../plugin_interface.h" + +class statistics_plugin: public webserver_plugin_interface  +{ +public: + statistics_plugin(); + ~statistics_plugin(); +  + std::string name(); + std::string generate_page( +  std::function<std::string(const std::string& key)>& GetServerParam, +  std::function<std::string(const std::string& key)>& GetRequestParam, // request including body (POST...) +  std::function<void(const std::string& key, const std::string& value)>& SetResponseHeader // to be added to result string + ); + +}; + +extern "C" BOOST_SYMBOL_EXPORT statistics_plugin webserver_plugin; +statistics_plugin webserver_plugin;  | 
