рефактор статических файлов, добавлено удобное API и поддержка кеширования
This commit is contained in:
@@ -85,77 +85,77 @@ namespace http::server {
|
||||
namespace stock_replies {
|
||||
constexpr char ok[] = "";
|
||||
constexpr char created[] =
|
||||
"<html>"
|
||||
"<!DOCTYPE html>\n<html>"
|
||||
"<head><title>Created</title></head>"
|
||||
"<body><h1>201 Created</h1></body>"
|
||||
"</html>";
|
||||
constexpr char accepted[] =
|
||||
"<html>"
|
||||
"<!DOCTYPE html>\n<html>"
|
||||
"<head><title>Accepted</title></head>"
|
||||
"<body><h1>202 Accepted</h1></body>"
|
||||
"</html>";
|
||||
constexpr char no_content[] =
|
||||
"<html>"
|
||||
"<!DOCTYPE html>\n<html>"
|
||||
"<head><title>No Content</title></head>"
|
||||
"<body><h1>204 Content</h1></body>"
|
||||
"</html>";
|
||||
constexpr char multiple_choices[] =
|
||||
"<html>"
|
||||
"<!DOCTYPE html>\n<html>"
|
||||
"<head><title>Multiple Choices</title></head>"
|
||||
"<body><h1>300 Multiple Choices</h1></body>"
|
||||
"</html>";
|
||||
constexpr char moved_permanently[] =
|
||||
"<html>"
|
||||
"<!DOCTYPE html>\n<html>"
|
||||
"<head><title>Moved Permanently</title></head>"
|
||||
"<body><h1>301 Moved Permanently</h1></body>"
|
||||
"</html>";
|
||||
constexpr char moved_temporarily[] =
|
||||
"<html>"
|
||||
"<!DOCTYPE html>\n<html>"
|
||||
"<head><title>Moved Temporarily</title></head>"
|
||||
"<body><h1>302 Moved Temporarily</h1></body>"
|
||||
"</html>";
|
||||
constexpr char not_modified[] =
|
||||
"<html>"
|
||||
"<!DOCTYPE html>\n<html>"
|
||||
"<head><title>Not Modified</title></head>"
|
||||
"<body><h1>304 Not Modified</h1></body>"
|
||||
"</html>";
|
||||
constexpr char bad_request[] =
|
||||
"<html>"
|
||||
"<!DOCTYPE html>\n<html>"
|
||||
"<head><title>Bad Request</title></head>"
|
||||
"<body><h1>400 Bad Request</h1></body>"
|
||||
"</html>";
|
||||
constexpr char unauthorized[] =
|
||||
"<html>"
|
||||
"<!DOCTYPE html>\n<html>"
|
||||
"<head><title>Unauthorized</title></head>"
|
||||
"<body><h1>401 Unauthorized</h1></body>"
|
||||
"</html>";
|
||||
constexpr char forbidden[] =
|
||||
"<html>"
|
||||
"<!DOCTYPE html>\n<html>"
|
||||
"<head><title>Forbidden</title></head>"
|
||||
"<body><h1>403 Forbidden</h1></body>"
|
||||
"</html>";
|
||||
constexpr char not_found[] =
|
||||
"<html>"
|
||||
"<!DOCTYPE html>\n<html>"
|
||||
"<head><title>Not Found</title></head>"
|
||||
"<body><h1>404 Not Found</h1></body>"
|
||||
"</html>";
|
||||
constexpr char internal_server_error[] =
|
||||
"<html>"
|
||||
"<!DOCTYPE html>\n<html>"
|
||||
"<head><title>Internal Server Error</title></head>"
|
||||
"<body><h1>500 Internal Server Error</h1></body>"
|
||||
"</html>";
|
||||
constexpr char not_implemented[] =
|
||||
"<html>"
|
||||
"<!DOCTYPE html>\n<html>"
|
||||
"<head><title>Not Implemented</title></head>"
|
||||
"<body><h1>501 Not Implemented</h1></body>"
|
||||
"</html>";
|
||||
constexpr char bad_gateway[] =
|
||||
"<html>"
|
||||
"<!DOCTYPE html>\n<html>"
|
||||
"<head><title>Bad Gateway</title></head>"
|
||||
"<body><h1>502 Bad Gateway</h1></body>"
|
||||
"</html>";
|
||||
constexpr char service_unavailable[] =
|
||||
"<html>"
|
||||
"<!DOCTYPE html>\n<html>"
|
||||
"<head><title>Service Unavailable</title></head>"
|
||||
"<body><h1>503 Service Unavailable</h1></body>"
|
||||
"</html>";
|
||||
|
@@ -1,6 +1,9 @@
|
||||
#include "resource.h"
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <fstream>
|
||||
#include <utility>
|
||||
|
||||
#include "../../dependencies/control_system/common/protocol_commands.h"
|
||||
|
||||
static void loadFile(const std::string& path, std::vector<char>& content) {
|
||||
std::ifstream is(path, std::ios::in | std::ios::binary);
|
||||
@@ -19,43 +22,59 @@ static void loadFile(const std::string& path, std::vector<char>& content) {
|
||||
}
|
||||
}
|
||||
|
||||
http::resource::StaticFileResource::StaticFileResource(const std::string &path, const std::string &filePath, server::mime_types::Mime type): type(type) {
|
||||
this->path = path;
|
||||
#ifdef USE_DEBUG
|
||||
BOOST_LOG_TRIVIAL(info) << "Skip loading file " << filePath << " (http path: " << path << ")";
|
||||
this->filePath = filePath;
|
||||
#else
|
||||
BOOST_LOG_TRIVIAL(info) << "Load file " << filePath << " (http path: " << path << ")";
|
||||
loadFile(filePath, this->content);
|
||||
#endif
|
||||
}
|
||||
http::resource::BasicResource::BasicResource(std::string path): path(std::move(path)) {}
|
||||
|
||||
void http::resource::StaticFileResource::handle(const server::Request &req, server::Reply &rep) {
|
||||
if (req.method != "GET") {
|
||||
stockReply(server::bad_request, rep);
|
||||
return;
|
||||
http::resource::StaticFileFactory::StaticFileDef::StaticFileDef(std::string path, server::mime_types::Mime type, bool allowCache): path(std::move(path)), type(type), allowCache(allowCache) {
|
||||
#ifdef USE_DEBUG
|
||||
if (allowCache) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Load static file " << this->path;
|
||||
loadFile(this->path, this->content);
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << "Skip loading static file " << this->path;
|
||||
}
|
||||
|
||||
// TODO сделать поддержку range
|
||||
#ifdef USE_DEBUG
|
||||
BOOST_LOG_TRIVIAL(debug) << "Reload file " << filePath << " (http path: " << path << ")";
|
||||
loadFile(this->filePath, rep.content);
|
||||
#else
|
||||
rep.content.clear();
|
||||
rep.content.insert(rep.content.end(), this->content.begin(), this->content.end());
|
||||
BOOST_LOG_TRIVIAL(info) << "Load static file " << this->path;
|
||||
loadFile(this->path, this->content);
|
||||
#endif
|
||||
rep.status = server::ok;
|
||||
rep.headers.clear();
|
||||
// TODO сделать cache control
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(this->type)});
|
||||
}
|
||||
http::resource::StaticFileFactory::StaticFileDef::~StaticFileDef() = default;
|
||||
|
||||
http::resource::StaticFileFactory::StaticFileFactory() = default;
|
||||
|
||||
void http::resource::StaticFileFactory::registerFile(const std::string &path, server::mime_types::Mime type, bool allowCache) {
|
||||
this->files.emplace_back(path, type, allowCache);
|
||||
}
|
||||
|
||||
http::resource::StaticFileResource::~StaticFileResource() = default;
|
||||
|
||||
http::resource::GenericResource::GenericResource(const std::string &path, const respGenerator &generator): generator_(generator) {
|
||||
this->path = path;
|
||||
void http::resource::StaticFileFactory::serve(const std::string &path, server::Reply &rep) {
|
||||
for (auto& f: this->files) {
|
||||
if (f.path == path) {
|
||||
#ifdef USE_DEBUG
|
||||
if (f.allowCache) {
|
||||
rep.content.clear();
|
||||
rep.content.insert(rep.content.end(), f.content.begin(), f.content.end());
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Reload file " << path << " (http path: " << path << ")";
|
||||
loadFile(f.path, rep.content);
|
||||
}
|
||||
#else
|
||||
rep.content.clear();
|
||||
rep.content.insert(rep.content.end(), f.content.begin(), f.content.end());
|
||||
#endif
|
||||
rep.status = server::ok;
|
||||
// rep.headers.clear();
|
||||
rep.headers.push_back({.name = "Content-Type", .value = server::mime_types::toString(f.type)});
|
||||
if (f.allowCache) {
|
||||
rep.headers.push_back({.name = "Cache-Control", .value = "max-age=86400"}); // сутки, думаю хватит
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
http::resource::StaticFileFactory::~StaticFileFactory() = default;
|
||||
|
||||
http::resource::GenericResource::GenericResource(const std::string &path, respGenerator generator): BasicResource(path), generator_(std::move(generator)) {}
|
||||
|
||||
void http::resource::GenericResource::handle(const server::Request &req, server::Reply &rep) {
|
||||
this->generator_(req, rep);
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@ namespace http::resource {
|
||||
*/
|
||||
class BasicResource {
|
||||
public:
|
||||
BasicResource(std::string path);
|
||||
std::string path;
|
||||
|
||||
virtual void handle(const server::Request &req, server::Reply &rep) = 0;
|
||||
@@ -19,24 +20,27 @@ namespace http::resource {
|
||||
virtual ~BasicResource() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* Класс ресурса статического файла
|
||||
*/
|
||||
class StaticFileResource final : public BasicResource {
|
||||
private:
|
||||
server::mime_types::Mime type;
|
||||
#ifdef USE_DEBUG
|
||||
std::string filePath;
|
||||
#else
|
||||
std::vector<char> content;
|
||||
#endif
|
||||
class StaticFileFactory {
|
||||
class StaticFileDef {
|
||||
public:
|
||||
StaticFileDef(std::string path, server::mime_types::Mime type, bool allowCache = true);
|
||||
|
||||
std::string path;
|
||||
server::mime_types::Mime type;
|
||||
bool allowCache;
|
||||
std::vector<char> content;
|
||||
|
||||
~StaticFileDef();
|
||||
};
|
||||
std::vector<StaticFileDef> files;
|
||||
public:
|
||||
StaticFileResource(const std::string& path, const std::string& filePath, server::mime_types::Mime type);
|
||||
StaticFileFactory();
|
||||
|
||||
void handle(const server::Request &req, server::Reply &rep) override;
|
||||
void registerFile(const std::string& path, server::mime_types::Mime type, bool allowCache = true);
|
||||
|
||||
~StaticFileResource() override;
|
||||
void serve(const std::string& path, server::Reply& rep);
|
||||
|
||||
~StaticFileFactory();
|
||||
};
|
||||
|
||||
using respGenerator = std::function<void(const server::Request &req, server::Reply &rep)>;
|
||||
@@ -49,7 +53,7 @@ namespace http::resource {
|
||||
respGenerator generator_;
|
||||
|
||||
public:
|
||||
GenericResource(const std::string& path, const respGenerator& generator);
|
||||
GenericResource(const std::string& path, respGenerator generator);
|
||||
|
||||
void handle(const server::Request &req, server::Reply &rep) override;
|
||||
|
||||
|
Reference in New Issue
Block a user