diff options
| author | Roland Reichwein <mail@reichwein.it> | 2020-05-10 18:18:37 +0200 | 
|---|---|---|
| committer | Roland Reichwein <mail@reichwein.it> | 2020-05-10 18:18:37 +0200 | 
| commit | 6c1cc0b2c854dd56dcb6238816a6ce2cb493c71c (patch) | |
| tree | de041dfb3bc12a04fa4defdbd286d098f34adddc | |
| parent | 5b32a4415c9776dd6cae859c8d718b5e68f01d81 (diff) | |
Separated out lib
| -rw-r--r-- | Makefile | 14 | ||||
| -rw-r--r-- | libcommon/Makefile | 123 | ||||
| -rw-r--r-- | libcommon/mime.cpp | 41 | ||||
| -rw-r--r-- | libcommon/mime.h | 5 | ||||
| -rw-r--r-- | plugins/cgi/Makefile | 11 | ||||
| -rw-r--r-- | plugins/cgi/cgi.cpp | 39 | ||||
| -rw-r--r-- | plugins/static-files/Makefile | 11 | ||||
| -rw-r--r-- | plugins/static-files/static-files.cpp | 40 | ||||
| -rw-r--r-- | plugins/webbox/Makefile | 11 | ||||
| -rw-r--r-- | plugins/webbox/webbox.cpp | 164 | ||||
| -rw-r--r-- | plugins/weblog/Makefile | 11 | ||||
| -rw-r--r-- | plugins/weblog/weblog.cpp | 41 | ||||
| -rw-r--r-- | response.cpp | 38 | 
13 files changed, 289 insertions, 260 deletions
@@ -50,7 +50,8 @@ LIBS=\  -lcrypt \  -lpthread \  -lssl -lcrypto \ --ldl +-ldl \ +-lcommon  #-lboost_coroutine \  #-lboost_program_options \ @@ -71,7 +72,7 @@ LIBS+= \  -lstdc++fs  endif -LDFLAGS+=-pie +LDFLAGS+=-pie -Llibcommon  PROGSRC=\      auth.cpp \ @@ -106,9 +107,12 @@ all: build  test-$(PROJECTNAME): $(TESTSRC:.cpp=.o)  	$(CXX) $(LDFLAGS) $^ $(LDLIBS) $(LIBS) -o $@ -$(PROJECTNAME): $(SRC:.cpp=.o) +$(PROJECTNAME): libcommon/libcommon.a $(SRC:.cpp=.o)  	$(CXX) $(LDFLAGS) $^ $(LDLIBS) $(LIBS) -o $@ +libcommon/libcommon.a: +	$(MAKE) -C libcommon +  dep: $(TESTSRC:.cpp=.d)  %.d: %.cpp @@ -157,6 +161,7 @@ clean:  	-rm -f plugins/*.so  	-find . -name '*.o' -o -name '*.d' -o -name '*.gcno' -o -name '*.gcda' | xargs rm -f  	for i in $(PLUGINS) ; do make -C plugins/$$i clean ; done +	$(MAKE) -C libcommon clean  DISTFILES= \  	archive.h \ @@ -206,6 +211,9 @@ DISTFILES= \  	debian/webserver.install \  	debian/webserver.manpages \  	debian/webserver.service \ +	libcommon/Makefile \ +	libcommon/mime.h \ +	libcommon/mime.cpp \  	plugins/cgi/cgi.h \  	plugins/cgi/Makefile \  	plugins/cgi/cgi.cpp \ diff --git a/libcommon/Makefile b/libcommon/Makefile new file mode 100644 index 0000000..3314549 --- /dev/null +++ b/libcommon/Makefile @@ -0,0 +1,123 @@ +# Static library to be included both in main program an in plugins (.so) + +DISTROS=debian10 +VERSION=$(shell dpkg-parsechangelog --show-field Version) +PROJECTNAME=libcommon + +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=\ +    mime.cpp + +TESTSRC=\ +    test-webserver.cpp \ +    googlemock/src/gmock-all.cpp \ +    googletest/src/gtest-all.cpp \ +    $(PROGSRC) + +SRC=$(PROGSRC) + +all: $(PROJECTNAME).a + +# testsuite ---------------------------------------------- +test-$(PROJECTNAME): $(TESTSRC:.cpp=.o) +	$(CXX) $(CXXFLAGS) $^ $(LIBS) -o $@ + +$(PROJECTNAME).a: $(SRC:.cpp=.o) +	ar rcs $@ $^ + +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 + + +# 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 '*.a' -o -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/libcommon/mime.cpp b/libcommon/mime.cpp new file mode 100644 index 0000000..f093596 --- /dev/null +++ b/libcommon/mime.cpp @@ -0,0 +1,41 @@ +#include "mime.h" + +#include <boost/beast/http.hpp> + +namespace beast = boost::beast;  + +// Return a reasonable mime type based on the extension of a file. +std::string mime_type(const std::string& path) +{ +    using beast::iequals; +    auto const ext = [&path] +    { +        auto const pos = path.rfind("."); +        if (pos == std::string::npos) +            return std::string{}; +        return path.substr(pos); +    }(); +    if(iequals(ext, ".htm"))  return "text/html"; +    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"; +} + diff --git a/libcommon/mime.h b/libcommon/mime.h new file mode 100644 index 0000000..c05eb45 --- /dev/null +++ b/libcommon/mime.h @@ -0,0 +1,5 @@ +#pragma once + +#include <string> + +std::string mime_type(const std::string& path); diff --git a/plugins/cgi/Makefile b/plugins/cgi/Makefile index b3e8548..8faebdc 100644 --- a/plugins/cgi/Makefile +++ b/plugins/cgi/Makefile @@ -19,7 +19,7 @@ endif  # -fprofile-instr-generate -fcoverage-mapping  # gcc:--coverage -CXXFLAGS+= -Wall -I. +CXXFLAGS+= -Wall -I. -I ../..  CXXFLAGS+= -pthread -fvisibility=hidden -fPIC  ifeq ($(CXX),clang++-10) @@ -40,7 +40,8 @@ LIBS=\  -lboost_regex \  -lpthread \  -lssl -lcrypto \ --ldl +-ldl \ +-lcommon  ifeq ($(CXX),clang++-10)  LIBS+= \ @@ -56,6 +57,8 @@ LIBS+= \  -lstdc++fs  endif +LDFLAGS=-L../../libcommon +  PROGSRC=\      cgi.cpp @@ -73,8 +76,8 @@ all: $(PROJECTNAME).so  test-$(PROJECTNAME): $(TESTSRC:.cpp=.o)  	$(CXX) $(CXXFLAGS) $^ $(LIBS) -o $@ -$(PROJECTNAME).so: $(SRC:.cpp=.o) -	$(CXX) -shared $(CXXFLAGS) $^ $(LIBS) -o $@ +$(PROJECTNAME).so: ../../libcommon/libcommon.a $(SRC:.cpp=.o) +	$(CXX) -shared $(LDFLAGS) $^ $(LDLIBS) $(LIBS) -o $@  dep: $(TESTSRC:.cpp=.d) diff --git a/plugins/cgi/cgi.cpp b/plugins/cgi/cgi.cpp index 0824d67..480ae9e 100644 --- a/plugins/cgi/cgi.cpp +++ b/plugins/cgi/cgi.cpp @@ -1,5 +1,7 @@  #include "cgi.h" +#include "libcommon/mime.h" +  #include <boost/algorithm/string/predicate.hpp>  #include <boost/coroutine2/coroutine.hpp>  #include <boost/process.hpp> @@ -45,41 +47,6 @@ 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"; -  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"; - } -   typedef boost::coroutines2::coroutine<std::string> coro_t;   // returns true iff std::string is empty or contains newline @@ -306,7 +273,7 @@ std::string cgi_plugin::generate_page(      return HttpStatus("500", "Bad file status access: "s + rel_target, SetResponseHeader);    } -  SetResponseHeader("content_type", mime_type(path)); +  SetResponseHeader("content_type", mime_type(path.string()));    CGIContext context(GetServerParam, GetRequestParam, SetResponseHeader, path, file_path, path_info); diff --git a/plugins/static-files/Makefile b/plugins/static-files/Makefile index fdc0896..e96257d 100644 --- a/plugins/static-files/Makefile +++ b/plugins/static-files/Makefile @@ -19,7 +19,7 @@ endif  # -fprofile-instr-generate -fcoverage-mapping  # gcc:--coverage -CXXFLAGS+= -Wall -I. +CXXFLAGS+= -Wall -I. -I../..  CXXFLAGS+= -pthread -fvisibility=hidden -fPIC  ifeq ($(CXX),clang++-10) @@ -40,7 +40,8 @@ LIBS=\  -lboost_regex \  -lpthread \  -lssl -lcrypto \ --ldl +-ldl \ +-lcommon  ifeq ($(CXX),clang++-10)  LIBS+= \ @@ -56,6 +57,8 @@ LIBS+= \  -lstdc++fs  endif +LDFLAGS=-L../../libcommon +  PROGSRC=\      static-files.cpp @@ -73,8 +76,8 @@ all: $(PROJECTNAME).so  test-$(PROJECTNAME): $(TESTSRC:.cpp=.o)  	$(CXX) $(CXXFLAGS) $^ $(LIBS) -o $@ -$(PROJECTNAME).so: $(SRC:.cpp=.o) -	$(CXX) -shared $(CXXFLAGS) $^ $(LIBS) -o $@ +$(PROJECTNAME).so: ../../libcommon/libcommon.a $(SRC:.cpp=.o) +	$(CXX) -shared $(LDFLAGS) $^ $(LDLIBS) $(LIBS) -o $@  dep: $(TESTSRC:.cpp=.d) diff --git a/plugins/static-files/static-files.cpp b/plugins/static-files/static-files.cpp index 011e37f..3f1c63a 100644 --- a/plugins/static-files/static-files.cpp +++ b/plugins/static-files/static-files.cpp @@ -1,5 +1,7 @@  #include "static-files.h" +#include "libcommon/mime.h" +  #include <boost/algorithm/string/predicate.hpp>  #include <filesystem> @@ -12,42 +14,6 @@ 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); @@ -126,7 +92,7 @@ std::string static_files_plugin::generate_page(     return HttpStatus("301", "Correcting directory path", SetResponseHeader);    }    path = {extend_index_html(path)}; -  SetResponseHeader("content_type", mime_type(path)); +  SetResponseHeader("content_type", mime_type(path.string()));    try {     return getFile(path); diff --git a/plugins/webbox/Makefile b/plugins/webbox/Makefile index 5ff22f7..1c49fda 100644 --- a/plugins/webbox/Makefile +++ b/plugins/webbox/Makefile @@ -19,7 +19,7 @@ endif  # -fprofile-instr-generate -fcoverage-mapping  # gcc:--coverage -CXXFLAGS+= -Wall -I. +CXXFLAGS+= -Wall -I. -I../..  CXXFLAGS+= -pthread -fvisibility=hidden -fPIC  ifeq ($(CXX),clang++-10) @@ -40,7 +40,8 @@ LIBS=\  -lboost_regex \  -lpthread \  -lssl -lcrypto \ --ldl +-ldl \ +-lcommon  ifeq ($(CXX),clang++-10)  LIBS+= \ @@ -56,6 +57,8 @@ LIBS+= \  -lstdc++fs  endif +LDFLAGS+=-L../../libcommon +  PROGSRC=\      file.cpp \      stringutil.cpp \ @@ -75,8 +78,8 @@ all: $(PROJECTNAME).so  test-$(PROJECTNAME): $(TESTSRC:.cpp=.o)  	$(CXX) $(CXXFLAGS) $^ $(LIBS) -o $@ -$(PROJECTNAME).so: $(SRC:.cpp=.o) -	$(CXX) -shared $(CXXFLAGS) $^ $(LIBS) -o $@ +$(PROJECTNAME).so: ../../libcommon/libcommon.a $(SRC:.cpp=.o) +	$(CXX) -shared $(LDFLAGS) $^ $(LDLIBS) $(LIBS) -o $@  dep: $(TESTSRC:.cpp=.d) diff --git a/plugins/webbox/webbox.cpp b/plugins/webbox/webbox.cpp index c58bd0c..53322b5 100644 --- a/plugins/webbox/webbox.cpp +++ b/plugins/webbox/webbox.cpp @@ -3,6 +3,8 @@  #include "file.h"  #include "stringutil.h" +#include "libcommon/mime.h" +  #include <boost/algorithm/string/predicate.hpp>  #include <boost/algorithm/string/replace.hpp>  #include <boost/algorithm/string/split.hpp> @@ -127,6 +129,9 @@ namespace {     std::function<std::string(const std::string& key)>& m_GetRequestParam; // request including body (POST...)     std::function<void(const std::string& key, const std::string& value)>& m_SetResponseHeader; // to be added to result string +   std::string m_pathInfo; // path inside webbox, derived from request +   fs::path m_path; // local filesystem path +     std::unordered_map<std::string, std::string> paramHash;     std::string webboxPath; @@ -150,14 +155,27 @@ namespace {     {      if (webboxStaticHtml == "")       webboxStaticHtml = STATIC_HTML_DOC_ROOT; +   +    m_pathInfo = urlDecode(GetRequestParam("rel_target")); +    size_t pos {m_pathInfo.find('?')}; +    if (pos != m_pathInfo.npos) { +     m_pathInfo = m_pathInfo.substr(0, pos); +    } + +    if (m_pathInfo.find("..") != m_pathInfo.npos) { +     throw std::runtime_error("Bad path: "s + m_pathInfo); +    } + +    m_path = webboxPath; +    if (!m_pathInfo.empty()) +     m_path /= m_pathInfo;     }   }; - // Used to return errors by generating response page and HTTP status code - std::string HttpStatus(std::string status, std::string message, CommandParameters& commandParameters) + std::string HttpStatus(std::string status, std::string message, std::function<void(const std::string& key, const std::string& value)>& SetResponseHeader)   { -  commandParameters.m_SetResponseHeader("status", status); -  commandParameters.m_SetResponseHeader("content_type", "text/html"); +  SetResponseHeader("status", status); +  SetResponseHeader("content_type", "text/html");    auto it{status_map.find(status)};    std::string description{"(Unknown)"}; @@ -167,6 +185,12 @@ namespace {    return "<html><body><h1>"s + status + " "s + description + "</h1><p>"s + message + "</p></body></html>";   } + // Used to return errors by generating response page and HTTP status code + std::string HttpStatus(std::string status, std::string message, CommandParameters& commandParameters) + { +  return HttpStatus(status, message, commandParameters.m_SetResponseHeader); + } +  } // anonymous namespace  class Command @@ -186,21 +210,6 @@ public:     return HttpStatus("403", "Bad request method", p);    } -  // Set parameters from FastCGI request environment -  m_pathInfo = urlDecode(p.m_GetRequestParam("rel_target")); -  size_t pos {m_pathInfo.find('?')}; -  if (pos != m_pathInfo.npos) { -   m_pathInfo = m_pathInfo.substr(0, pos); -  } - -  if (m_pathInfo.find("..") != m_pathInfo.npos) { -   return HttpStatus("403", "Bad path: "s + m_pathInfo, p); -  } - -  m_path = p.webboxPath; -  if (!m_pathInfo.empty()) -   m_path /= m_pathInfo; -    return this->start(p);   } @@ -220,9 +229,6 @@ protected:   std::string m_requestMethod;   bool m_isWriteCommand; // if true, command must be prevented if p.webboxReadOnly - // calculated during start of execute() - std::string m_pathInfo; // path inside webbox, derived from request - fs::path m_path; // local filesystem path  };  class GetCommand: public Command @@ -306,13 +312,13 @@ protected:    pt::ptree list;    pt::ptree entry; -  if (m_pathInfo != ""s) { // Add ".." if not in top directory of this webbox +  if (p.m_pathInfo != ""s) { // Add ".." if not in top directory of this webbox     entry.put_value("..");     entry.put("<xmlattr>.type", "dir");     list.push_back(pt::ptree::value_type("listentry", entry));    } -  fs::directory_iterator dir(m_path); +  fs::directory_iterator dir(p.m_path);    std::vector<std::string> files;    std::vector<std::string> dirs; @@ -412,7 +418,7 @@ protected:    std::string dirname = tree.get<std::string>("dirname");    try { -   if (fs::create_directory(m_path / dirname)) +   if (fs::create_directory(p.m_path / dirname))      return "Successfully created directory";     else      return "Error creating directory"; @@ -449,7 +455,7 @@ protected:     for (const auto& element: elements) {      if (element.first == "file"s) {       std::string filename{element.second.data()}; -     fs::path path {m_path / filename}; +     fs::path path {p.m_path / filename};       auto filesize {fs::file_size(path)}; @@ -514,7 +520,7 @@ protected:     return HttpStatus("400", "No files found", p);    try { -   fs::current_path(m_path); +   fs::current_path(p.m_path);    } catch (const std::exception& ex) {     return HttpStatus("500", "Change path error: "s + ex.what(), p);    } @@ -566,7 +572,7 @@ protected:      if (element.first == "file"s) {       std::string filename{element.second.data()}; -     fs::path path{m_path / filename}; +     fs::path path{p.m_path / filename};       if (fs::is_directory(path)) {        try { @@ -624,10 +630,10 @@ protected:     auto elements {tree.get_child("request")};     for (const auto& element: elements) {      if (element.first == "target") { -     targetDir = m_path / element.second.data(); +     targetDir = p.m_path / element.second.data();      } else if (element.first == "file") {       std::string filename{element.second.data()}; -     fs::path old_path{m_path / filename}; +     fs::path old_path{p.m_path / filename};       fs::path new_path{targetDir / filename};       try {        fs::rename(old_path, new_path); @@ -674,8 +680,8 @@ protected:    std::string oldname{tree.get<std::string>("request.oldname")};    std::string newname{tree.get<std::string>("request.newname")}; -  fs::path oldpath{m_path / oldname}; -  fs::path newpath{m_path / newname}; +  fs::path oldpath{p.m_path / oldname}; +  fs::path newpath{p.m_path / newname};    try {     fs::rename(oldpath, newpath); @@ -753,7 +759,7 @@ protected:          } else {           filecontent = filecontent.substr(start + "\r\n\r\n"s.size()); -         fs::path path{ m_path / filename}; +         fs::path path{ p.m_path / filename};           try {            File::setFile(path, filecontent);           } catch (const std::exception& ex) { @@ -784,54 +790,18 @@ protected:   virtual std::string start(CommandParameters& p)   {    try { -   std::string result{File::getFile(m_path)}; +   std::string result{File::getFile(p.m_path)}; -   p.m_SetResponseHeader("content_disposition", "attachment; filename=\""s + m_path.filename().string() + "\""s); +   p.m_SetResponseHeader("content_disposition", "attachment; filename=\""s + p.m_path.filename().string() + "\""s);     p.m_SetResponseHeader("content_type", "application/octet-stream");     return result;    } catch (const std::exception& ex) { -   return HttpStatus("404", "Bad file: "s + m_path.filename().string(), p); +   return HttpStatus("404", "Bad file: "s + p.m_path.filename().string(), p);    }   }  }; -// Return a reasonable mime type based on the extension of a file. -static 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"; -} -  class StaticHtmlCommand: public GetCommand  {  public: @@ -846,7 +816,7 @@ protected:   {    // redirect to xyz/ if xyz was requested    std::string target = p.m_GetRequestParam("target"); -  if (m_pathInfo == "" && !target.empty() && target.back() != '/') { +  if (p.m_pathInfo == "" && !target.empty() && target.back() != '/') {     p.m_SetResponseHeader("location", target + "/");     return HttpStatus("301", "Use correct index: /"s, p);    }  @@ -854,20 +824,20 @@ protected:    try {     fs::path file_path; -   if (m_pathInfo == "/" || m_pathInfo == "") { +   if (p.m_pathInfo == "/" || p.m_pathInfo == "") {      file_path = p.webboxStaticHtml / "index.html"; -   } else if (boost::algorithm::starts_with(m_pathInfo, STATIC_HTML_TARGET)) { -    file_path = p.webboxStaticHtml / m_pathInfo.substr(STATIC_HTML_TARGET.size()); +   } else if (boost::algorithm::starts_with(p.m_pathInfo, STATIC_HTML_TARGET)) { +    file_path = p.webboxStaticHtml / p.m_pathInfo.substr(STATIC_HTML_TARGET.size());     } else { -    return HttpStatus("500", "Bad request: "s + m_pathInfo, p); +    return HttpStatus("500", "Bad request: "s + p.m_pathInfo, p);     } -   p.m_SetResponseHeader("content_type", mime_type(file_path)); +   p.m_SetResponseHeader("content_type", mime_type(file_path.string()));     std::string result{File::getFile(file_path)};     return result;    } catch (const std::exception& ex) { -   return HttpStatus("500", "Server error: "s + m_pathInfo, p); +   return HttpStatus("500", "Server error: "s + p.m_pathInfo, p);    }   }  }; @@ -908,23 +878,27 @@ std::string webbox_plugin::generate_page(  {   // Queries under STATIC_HTML_TARGET will be served statically from STATIC_HTML_DOC_ROOT - CommandParameters commandParameters(GetServerParam, GetRequestParam, SetResponseHeader); -  - std::string commandName; -  - auto it {commandParameters.paramHash.find("command")}; - if (it != commandParameters.paramHash.end()) -  commandName = it->second; + try { +  CommandParameters commandParameters(GetServerParam, GetRequestParam, SetResponseHeader); +   +  std::string commandName; +   +  auto it {commandParameters.paramHash.find("command")}; +  if (it != commandParameters.paramHash.end()) +   commandName = it->second; - auto commands_it{m_commands.find(commandName)}; - if (commands_it != m_commands.end()) { -  try { -   return commands_it->second->execute(commandParameters); -  } catch (const std::exception& ex) { -   return HttpStatus("500", "Processing command: "s + commandName + ", "s + ex.what(), commandParameters); -  } - } else -  return HttpStatus("400", "Bad command: "s + commandName, commandParameters); +  auto commands_it{m_commands.find(commandName)}; +  if (commands_it != m_commands.end()) { +   try { +    return commands_it->second->execute(commandParameters); +   } catch (const std::exception& ex) { +    return HttpStatus("500", "Processing command: "s + commandName + ", "s + ex.what(), commandParameters); +   } +  } else +   return HttpStatus("400", "Bad command: "s + commandName, commandParameters); + } catch (const std::exception& ex) { +  return HttpStatus("500", ex.what(), SetResponseHeader); + }  }  void webbox_plugin::registerCommand(std::shared_ptr<Command> command) diff --git a/plugins/weblog/Makefile b/plugins/weblog/Makefile index 58d1801..b9f278a 100644 --- a/plugins/weblog/Makefile +++ b/plugins/weblog/Makefile @@ -19,7 +19,7 @@ endif  # -fprofile-instr-generate -fcoverage-mapping  # gcc:--coverage -CXXFLAGS+= -Wall -I. +CXXFLAGS+= -Wall -I. -I../..  CXXFLAGS+= -pthread -fvisibility=hidden -fPIC  ifeq ($(CXX),clang++-10) @@ -40,7 +40,8 @@ LIBS=\  -lboost_regex \  -lpthread \  -lssl -lcrypto \ --ldl +-ldl \ +-lcommon  ifeq ($(CXX),clang++-10)  LIBS+= \ @@ -56,6 +57,8 @@ LIBS+= \  -lstdc++fs  endif +LDFLAGS=-L../../libcommon +  PROGSRC=\      stringutil.cpp \      weblog.cpp @@ -74,8 +77,8 @@ all: $(PROJECTNAME).so  test-$(PROJECTNAME): $(TESTSRC:.cpp=.o)  	$(CXX) $(CXXFLAGS) $^ $(LIBS) -o $@ -$(PROJECTNAME).so: $(SRC:.cpp=.o) -	$(CXX) -shared $(CXXFLAGS) $^ $(LIBS) -o $@ +$(PROJECTNAME).so: ../../libcommon/libcommon.a $(SRC:.cpp=.o) +	$(CXX) -shared $(LDFLAGS) $^ $(LDLIBS) $(LIBS) -o $@  dep: $(TESTSRC:.cpp=.d) diff --git a/plugins/weblog/weblog.cpp b/plugins/weblog/weblog.cpp index 4ed468e..4a14799 100644 --- a/plugins/weblog/weblog.cpp +++ b/plugins/weblog/weblog.cpp @@ -2,6 +2,8 @@  #include "stringutil.h" +#include "libcommon/mime.h" +  #include <boost/algorithm/string/predicate.hpp>  #include <boost/algorithm/string/replace.hpp>  #include <boost/property_tree/ptree.hpp> @@ -23,41 +25,6 @@ namespace {   const size_t number_of_articles_on_front_page {10};   const std::string article_filename{"article.data"}; - // 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"; - } -   // 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)   { @@ -92,7 +59,7 @@ namespace {   bool is_index_file(std::string& rel_target, fs::path& path)   {    // must be top-level file, recognized as mime_type() -  return rel_target.find("/") == rel_target.npos && mime_type(path) != "application/text"; +  return rel_target.find("/") == rel_target.npos && mime_type(path.string()) != "application/text";   }   bool is_article_page(std::string& rel_target, fs::path& path) @@ -344,7 +311,7 @@ namespace {   std::string generateStaticFile(fs::path& path, std::function<plugin_interface_setter_type>& SetResponseHeader)   {    try { -   SetResponseHeader("content_type", mime_type(path)); +   SetResponseHeader("content_type", mime_type(path.string()));     return getFile(path);    } catch (const std::exception& ex) {     return HttpStatus("500", "Reading Article file: "s + ex.what(), SetResponseHeader); diff --git a/response.cpp b/response.cpp index 2320379..4c76bb3 100644 --- a/response.cpp +++ b/response.cpp @@ -5,6 +5,8 @@  #include "file.h"  #include "os.h" +#include "libcommon/mime.h" +  #include <boost/algorithm/string/predicate.hpp>  #include <functional> @@ -202,42 +204,6 @@ void SetResponseHeader(const std::string& key, const std::string& value, respons    throw std::runtime_error("Unsupported response field: "s + key);  } -// Return a reasonable mime type based on the extension of a file. -beast::string_view -mime_type(beast::string_view path) -{ -    using beast::iequals; -    auto const ext = [&path] -    { -        auto const pos = path.rfind("."); -        if (pos == beast::string_view::npos) -            return beast::string_view{}; -        return path.substr(pos); -    }(); -    if(iequals(ext, ".htm"))  return "text/html"; -    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"; -} -  response_type HttpStatus(std::string status, std::string message, response_type& res)  {   if (status != "200") { // already handled at res init  | 
