1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
#include "common.hh"
#include "files_finder.hh"
#include "hasher.hh"
#include "mime_types.hh"
#include "send_file.hh"
#include "static_files.hh"
#include "weak_ptr.hh"
#include <optional>
namespace {
class StaticFilesImpl : public StaticFiles, public FilesFinder::Delegate {
public:
StaticFilesImpl(
std::shared_ptr<Logger> logger,
std::shared_ptr<TaskRunner> runner,
std::shared_ptr<SendFile> send_file,
std::filesystem::path path,
size_t threads)
: root_(std::move(path)), send_file_(std::move(send_file)),
weak_ptr_owner_(this) {
finder_ = FilesFinder::create(logger, runner, root_, this, threads);
hasher_ = Hasher::create(logger, runner, threads);
}
std::unique_ptr<Transport::Response> request(
Transport* transport, std::string_view path) override {
auto it = files_.find(std::string(path));
if (it == files_.end())
return nullptr;
auto resp = send_file_->create_ok_file(transport, it->second.path_,
it->first, it->second.etag_,
it->second.size_);
if (!it->second.mime_type_.empty())
resp->add_header("Content-Type", it->second.mime_type_);
return resp;
}
void file(std::filesystem::path path) override {
std::string name("/");
name.append(path.filename());
auto parent = path.parent_path();
while (true) {
if (parent == root_ || !parent.has_parent_path())
break;
name.insert(0, parent.filename());
name.insert(0, "/");
parent = parent.parent_path();
}
files_[name].path_ = path;
if (path.has_extension())
files_[name].mime_type_ = mime_types::from_extension(
std::string(path.extension()).substr(1));
hasher_->hash(path, std::bind(&StaticFilesImpl::weak_hashed,
weak_ptr_owner_.get(), name,
std::placeholders::_1,
std::placeholders::_2));
}
void done() override {
finder_.reset();
}
private:
struct File {
std::filesystem::path path_;
std::string mime_type_;
std::string etag_;
std::optional<uint64_t> size_;
};
static void weak_hashed(std::shared_ptr<WeakPtr<StaticFilesImpl>> weak_ptr,
std::string const& name,
std::string hash,
uint64_t size) {
auto* ptr = weak_ptr->get();
if (ptr)
ptr->hashed(name, std::move(hash), size);
}
void hashed(std::string const& name, std::string hash, uint64_t size) {
if (hash.empty())
return;
hash.insert(0, "\"");
hash.push_back('"');
files_[name].etag_ = std::move(hash);
files_[name].size_ = size;
}
std::filesystem::path root_;
std::shared_ptr<SendFile> send_file_;
std::unordered_map<std::string, File> files_;
std::unique_ptr<FilesFinder> finder_;
std::unique_ptr<Hasher> hasher_;
WeakPtrOwner<StaticFilesImpl> weak_ptr_owner_;
};
} // namespace
std::unique_ptr<StaticFiles> StaticFiles::create(
std::shared_ptr<Logger> logger,
std::shared_ptr<TaskRunner> runner,
std::shared_ptr<SendFile> send_file,
std::filesystem::path path,
size_t threads) {
return std::make_unique<StaticFilesImpl>(
std::move(logger), std::move(runner), std::move(send_file),
std::move(path), threads);
}
|