summaryrefslogtreecommitdiffhomepage
path: root/response.cpp
diff options
context:
space:
mode:
authorRoland Reichwein <mail@reichwein.it>2020-04-05 19:15:25 +0200
committerRoland Reichwein <mail@reichwein.it>2020-04-05 19:15:25 +0200
commit917d4574153fa57ea43e7410006f58aa5b1bbb0b (patch)
tree3d4535370f596a46740a434319e73daf7f2704ba /response.cpp
parentddc02ba7a6cc92d07cf073395b2d41347a8d35fb (diff)
Separate out response handling
Diffstat (limited to 'response.cpp')
-rw-r--r--response.cpp92
1 files changed, 92 insertions, 0 deletions
diff --git a/response.cpp b/response.cpp
new file mode 100644
index 0000000..78368f6
--- /dev/null
+++ b/response.cpp
@@ -0,0 +1,92 @@
+#include "response.h"
+#include "file.h"
+
+namespace {
+
+// Append an HTTP rel-path to a local filesystem path.
+// The returned path is normalized for the platform.
+std::string
+path_cat(
+ beast::string_view base,
+ beast::string_view path)
+{
+ if(base.empty())
+ return std::string(path);
+ std::string result(base);
+#ifdef BOOST_MSVC
+ char constexpr path_separator = '\\';
+ if(result.back() == path_separator)
+ result.resize(result.size() - 1);
+ result.append(path.data(), path.size());
+ for(auto& c : result)
+ if(c == '/')
+ c = path_separator;
+#else
+ char constexpr path_separator = '/';
+ if(result.back() == path_separator)
+ result.resize(result.size() - 1);
+ result.append(path.data(), path.size());
+#endif
+ return result;
+}
+
+}
+
+http_exception::http_exception(std::string message): m_message(message)
+{
+}
+
+const char* http_exception::what() const noexcept
+{
+ return m_message.data();
+}
+
+bad_request_exception::bad_request_exception(std::string message): http_exception(message)
+{
+}
+
+not_found_exception::not_found_exception(std::string message): http_exception(message)
+{
+}
+
+server_error_exception::server_error_exception(std::string message): http_exception(message)
+{
+}
+
+std::string extend_index_html(std::string path)
+{
+ if (path.size() && path.back() == '/')
+ path.append("index.html");
+ return path;
+}
+
+std::string generate_response(http::request<http::string_body>& req, const Config& config, const Socket& socket)
+{
+ // Make sure we can handle the method
+ if( req.method() != http::verb::get &&
+ req.method() != http::verb::head)
+ throw bad_request_exception("Unknown HTTP-method");
+
+ // Request path must be absolute and not contain "..".
+ if( req.target().empty() ||
+ req.target()[0] != '/' ||
+ req.target().find("..") != beast::string_view::npos)
+ throw bad_request_exception("Illegal request-target");
+
+ // Build the path to the requested file
+ std::string host{req["host"]}; // TODO: just use string_view
+ std::string target{req.target()};
+ std::string path = path_cat(config.DocRoot(socket, host, target), extend_index_html(std::string(req.target())));
+
+ std::string result;
+ try {
+ result = File::getFile(path);
+ } catch (const std::runtime_error& ex) {
+ throw not_found_exception(std::string(req.target()));
+ } catch (const std::exception& ex) {
+ throw server_error_exception(ex.what());
+ }
+
+ return result;
+}
+