summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--debian/changelog6
-rw-r--r--plugins/weblog/Makefile16
-rw-r--r--plugins/weblog/weblog.cpp121
-rw-r--r--plugins/weblog/weblog.h10
-rw-r--r--webserver.conf4
6 files changed, 143 insertions, 16 deletions
diff --git a/Makefile b/Makefile
index bc4977b..de0ce07 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
DISTROS=debian10
VERSION=$(shell dpkg-parsechangelog --show-field Version)
PROJECTNAME=webserver
-PLUGINS=static-files webbox cgi # weblog fcgi
+PLUGINS=static-files webbox cgi weblog # fcgi
CXX=clang++-10
diff --git a/debian/changelog b/debian/changelog
index d9802d9..64bc601 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+webserver (1.2) unstable; urgency=medium
+
+ * Added Weblog module
+
+ -- Roland Reichwein <rr@antcom.de> Sun, 19 Apr 2020 19:07:24 +0200
+
webserver (1.1) unstable; urgency=medium
* Added CGI
diff --git a/plugins/weblog/Makefile b/plugins/weblog/Makefile
index 27b68fc..ffd31e1 100644
--- a/plugins/weblog/Makefile
+++ b/plugins/weblog/Makefile
@@ -25,7 +25,7 @@ CXXFLAGS+= -pthread -fvisibility=hidden -fPIC
ifeq ($(CXX),clang++-10)
CXXFLAGS+=-std=c++20 #-stdlib=libc++
else
-CXXFLAGS+=-std=c++2a
+CXXFLAGS+=-std=c++17
endif
CXXTESTFLAGS=-Igoogletest/include -Igooglemock/include/ -Igoogletest -Igooglemock
@@ -52,8 +52,8 @@ LIBS+= \
#-lstdc++fs
else
LIBS+= \
--lstdc++
-#-lstdc++fs
+-lstdc++ \
+-lstdc++fs
endif
PROGSRC=\
@@ -92,14 +92,8 @@ googletest/src/%.o: googletest/src/%.cc
ADD_DEP=Makefile
install:
- mkdir -p $(DESTDIR)/usr/bin
- cp webserver $(DESTDIR)/usr/bin
-
mkdir -p $(DESTDIR)/usr/lib/webserver/plugins
- mkdir -p $(DESTDIR)/usr/local/lib/webserver/plugins
-
- mkdir -p $(DESTDIR)/etc
- cp webserver.conf $(DESTDIR)/etc/webserver.conf
+ cp $(PROJECTNAME).so $(DESTDIR)/usr/lib/webserver/plugins
# misc ---------------------------------------------------
deb:
@@ -116,7 +110,7 @@ debs: $(DISTROS)
clean:
-rm -f test-$(PROJECTNAME) $(PROJECTNAME)
- -find . -name '*.o' -o -name '*.d' -o -name '*.gcno' -o -name '*.gcda' | xargs rm -f
+ -find . -name '*.o' -o -name '*.so' -o -name '*.d' -o -name '*.gcno' -o -name '*.gcda' | xargs rm -f
zip: clean
-rm -f ../$(PROJECTNAME).zip
diff --git a/plugins/weblog/weblog.cpp b/plugins/weblog/weblog.cpp
index ef90a53..1c58b73 100644
--- a/plugins/weblog/weblog.cpp
+++ b/plugins/weblog/weblog.cpp
@@ -1,8 +1,90 @@
#include "weblog.h"
+#include <boost/algorithm/string/predicate.hpp>
+
+#include <filesystem>
+#include <fstream>
#include <iostream>
+#include <string>
using namespace std::string_literals;
+namespace fs = std::filesystem;
+
+namespace {
+
+// Return a reasonable mime type based on the extension of a file.
+std::string
+mime_type(fs::path path)
+{
+ using boost::algorithm::iequals;
+ auto const ext = [&path]
+ {
+ size_t pos = path.string().rfind(".");
+ if (pos == std::string::npos)
+ return std::string{};
+ return path.string().substr(pos);
+ }();
+ if(iequals(ext, ".htm")) return "text/html"; // TODO: unordered_map
+ if(iequals(ext, ".html")) return "text/html";
+ if(iequals(ext, ".php")) return "text/html";
+ if(iequals(ext, ".css")) return "text/css";
+ if(iequals(ext, ".txt")) return "text/plain";
+ if(iequals(ext, ".js")) return "application/javascript";
+ if(iequals(ext, ".json")) return "application/json";
+ if(iequals(ext, ".xml")) return "application/xml";
+ if(iequals(ext, ".swf")) return "application/x-shockwave-flash";
+ if(iequals(ext, ".flv")) return "video/x-flv";
+ if(iequals(ext, ".png")) return "image/png";
+ if(iequals(ext, ".jpe")) return "image/jpeg";
+ if(iequals(ext, ".jpeg")) return "image/jpeg";
+ if(iequals(ext, ".jpg")) return "image/jpeg";
+ if(iequals(ext, ".gif")) return "image/gif";
+ if(iequals(ext, ".bmp")) return "image/bmp";
+ if(iequals(ext, ".ico")) return "image/vnd.microsoft.icon";
+ if(iequals(ext, ".tiff")) return "image/tiff";
+ if(iequals(ext, ".tif")) return "image/tiff";
+ if(iequals(ext, ".svg")) return "image/svg+xml";
+ if(iequals(ext, ".svgz")) return "image/svg+xml";
+ return "application/text";
+}
+
+std::string getFile(const fs::path& filename)
+{
+ std::ifstream file(filename.string(), std::ios::in | std::ios::binary | std::ios::ate);
+
+ if (file.is_open()) {
+ std::ifstream::pos_type fileSize = file.tellg();
+ file.seekg(0, std::ios::beg);
+
+ std::string bytes(fileSize, ' ');
+ file.read(reinterpret_cast<char*>(bytes.data()), fileSize);
+
+ return bytes;
+
+ } else {
+ throw std::runtime_error("Opening "s + filename.string() + " for reading");
+ }
+}
+
+bool is_index_page(std::string& path)
+{
+ return (path.size() == 0 || path.back() == '/');
+}
+
+std::string generateIndexPage(std::function<plugin_interface_setter_type>& SetResponseHeader)
+{
+ return "<html><body><h1>Blog</h1></body></html>";
+}
+
+// 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;
+}
+
+}
std::string weblog_plugin::name()
{
@@ -19,8 +101,43 @@ weblog_plugin::~weblog_plugin()
//std::cout << "Plugin destructor" << std::endl;
}
-std::string weblog_plugin::generate_page(std::string path)
+std::string weblog_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
+)
{
- return "Blog "s + path;
+ try {
+ // Make sure we can handle the method
+ std::string method {GetRequestParam("method")};
+ if (method != "GET" && method != "HEAD")
+ return HttpStatus("400", "Unknown HTTP method", SetResponseHeader);
+
+ // Request path must not contain "..".
+ std::string rel_target{GetRequestParam("rel_target")};
+ 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);
+ }
+
+ SetResponseHeader("content_type", "text/html");
+
+ if (is_index_page(rel_target))
+ return generateIndexPage(SetResponseHeader);
+
+ return HttpStatus("404", "Bad path specification: "s + rel_target, SetResponseHeader);
+
+ } catch (const std::exception& ex) {
+ return HttpStatus("500", "Unknown Error: "s + ex.what(), SetResponseHeader);
+ }
}
diff --git a/plugins/weblog/weblog.h b/plugins/weblog/weblog.h
index 5433e1c..28b4ab3 100644
--- a/plugins/weblog/weblog.h
+++ b/plugins/weblog/weblog.h
@@ -1,14 +1,20 @@
#pragma once
-#include "../plugin_interface.h"
+#include "../../plugin_interface.h"
class weblog_plugin: public webserver_plugin_interface
{
public:
weblog_plugin();
~weblog_plugin();
+
std::string name();
- std::string generate_page(std::string path);
+ 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 weblog_plugin webserver_plugin;
diff --git a/webserver.conf b/webserver.conf
index 46046d9..16ac3e0 100644
--- a/webserver.conf
+++ b/webserver.conf
@@ -31,6 +31,10 @@
<WEBBOX_READONLY>0</WEBBOX_READONLY>
<auth login="abc" password="def"/>
</path>
+ <path requested="/blog">
+ <plugin>weblog</plugin>
+ <target>/home/ernie/testblog</target>
+ </path>
<path requested="/cgi-bin">
<plugin>cgi</plugin>
<target>/home/ernie/code/webserver/cgi-bin</target>