Haio 0.2.X
Homebrew Asset IO/CDN
Loading...
Searching...
No Matches
bucket.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <haio_cdn.hpp>
4
5#include <boost/asio/awaitable.hpp>
6
7#include <list>
8#include <map>
9#include <memory>
10#include <optional>
11#include <stdexcept>
12#include <string>
13#include <vector>
14
15/**
16 * one directory per way of reaching bytes, the way the codecs do it. the dispatcher in
17 * buckets.cpp picks by the scheme the config parsed, and each fetcher only knows its
18 * own protocol.
19 */
20namespace Haio::Cdn::Bucket {
21
22/**
23 * carries why it failed, so the http layer does not have to guess from the text.
24 *
25 * it is not called Error because Haio::Error already is, and the two are different
26 * things: this one is thrown between the fetchers, that one is returned to a caller.
27 */
28struct Failure : std::runtime_error {
30 Failure(Haio::ErrorCode why, const std::string& what) : std::runtime_error(what), code(why) {}
31};
32
33/** file:// buckets: a directory on this machine, and never a step above it */
34Blob fetchFile(const BucketConfig& bucket, std::string path);
35
36/** headers a caller adds to the request, which is how s3 carries its signature */
37using Headers = std::map<std::string, std::string>;
38
39/** http and https buckets, open or with a fixed endpoint */
40boost::asio::awaitable<Blob> fetchHttp(const BucketConfig& bucket, std::string path);
41
42/** the same fetch, with headers somebody else worked out */
43boost::asio::awaitable<Blob> fetchUrlWith(std::string url, std::string pathForFormat, Headers headers);
44
45/**
46 * s3 buckets, which are https with a signature.
47 *
48 * the credentials come from the environment, the way every other aws tool reads them,
49 * so nothing secret is ever written in the config file.
50 */
51boost::asio::awaitable<Blob> fetchS3(const BucketConfig& bucket, std::string path);
52
53/**
54 * the signature part of sigv4, on its own so it can be checked against the vectors
55 * aws publishes. the key is derived over date, region and service and then used over
56 * the string to sign; getting the last step wrong yields something that looks like a
57 * signature and is refused exactly like a wrong secret.
58 */
59std::string awsSignatureV4(std::string_view secret, std::string_view date, std::string_view region,
60 std::string_view service, std::string_view stringToSign);
61
62/** where one file sits inside an archive, as the zip's own directory records it */
63struct ZipEntry {
64 uint32_t at = 0;
65 uint32_t compressed = 0;
66 uint32_t uncompressed = 0;
67 uint16_t method = 0;
68};
69
70struct ZipIndex {
71 std::map<std::string, ZipEntry> entries;
72};
73
75Result<std::vector<uint8_t>> readZipEntry(Bytes data, const ZipEntry& entry, size_t maxSize);
76
77/**
78 * "pack.zip/logo.png" split into the archive and the name inside it, or nothing when
79 * the path names no archive. the split is on the first ".zip/", so an archive inside
80 * an archive is read as a file inside the outer one rather than opened again.
81 */
82struct ZipPath {
83 std::string archive;
84 std::string inside;
85};
86std::optional<ZipPath> splitZipPath(std::string_view path);
87
88class ZipArchives;
89boost::asio::awaitable<Blob> fetchInsideZip(const BucketConfig& bucket, const ZipPath& path,
90 const SecurityConfig& security, ZipArchives& archives);
91
92/**
93 * the archives themselves, kept apart from the response cache because what they hold
94 * is not an answer: a request for a second picture out of the same zip should not
95 * have to fetch it again, and a request for the same picture never reaches here at
96 * all, since the response cache already answered.
97 */
99public:
100 explicit ZipArchives(size_t maxUsage);
101
102 struct Archive {
103 std::vector<uint8_t> data;
105 };
106
107 std::shared_ptr<const Archive> find(const std::string& key);
108 std::shared_ptr<const Archive> keep(const std::string& key, std::vector<uint8_t> data, ZipIndex index);
109
110private:
111 struct Held {
112 std::string key;
113 std::shared_ptr<const Archive> archive;
114 size_t size = 0;
115 };
116
117 size_t maxUsage_;
118 size_t held_ = 0;
119 std::list<Held> order_;
120 std::map<std::string, std::list<Held>::iterator> index_;
121};
122
123}
std::shared_ptr< const Archive > keep(const std::string &key, std::vector< uint8_t > data, ZipIndex index)
Definition archives.cpp:28
std::shared_ptr< const Archive > find(const std::string &key)
Definition archives.cpp:20
ZipArchives(size_t maxUsage)
Definition archives.cpp:18
Result< std::vector< uint8_t > > readZipEntry(Bytes data, const ZipEntry &entry, size_t maxSize)
Definition reader.cpp:106
std::map< std::string, std::string > Headers
Definition bucket.hpp:37
std::optional< ZipPath > splitZipPath(std::string_view path)
Definition archives.cpp:6
boost::asio::awaitable< Blob > fetchS3(const BucketConfig &bucket, std::string path)
Definition s3.cpp:130
boost::asio::awaitable< Blob > fetchUrlWith(std::string url, std::string pathForFormat, Headers headers)
Definition http.cpp:244
boost::asio::awaitable< Blob > fetchHttp(const BucketConfig &bucket, std::string path)
Definition http.cpp:253
boost::asio::awaitable< Blob > fetchInsideZip(const BucketConfig &bucket, const ZipPath &path, const SecurityConfig &security, ZipArchives &archives)
Definition fetch.cpp:16
Result< ZipIndex > readZipIndex(Bytes data)
Definition reader.cpp:57
std::string awsSignatureV4(std::string_view secret, std::string_view date, std::string_view region, std::string_view service, std::string_view stringToSign)
Definition s3.cpp:113
std::map< std::string, ZipEntry > entries
Definition bucket.hpp:71
Blob fetchFile(const BucketConfig &bucket, std::string path)
Definition file.cpp:54
std::expected< T, Error > Result
std::span< const uint8_t > Bytes
Failure(Haio::ErrorCode why, const std::string &what)
Definition bucket.hpp:30
Haio::ErrorCode code
Definition bucket.hpp:29