Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/plugins/s3_auth/s3_auth.cc b/plugins/s3_auth/s3_auth.cc
- index a52b07fa1..7dc92fc03 100644
- --- a/plugins/s3_auth/s3_auth.cc
- +++ b/plugins/s3_auth/s3_auth.cc
- @@ -27,6 +27,10 @@
- #include <stdlib.h>
- #include <limits.h>
- #include <ctype.h>
- +#include <sys/time.h>
- +
- +#include <string>
- +#include <unordered_map>
- #include <openssl/sha.h>
- #include <openssl/hmac.h>
- @@ -42,6 +46,24 @@ static const char PLUGIN_NAME[] = "s3_auth";
- static const char DATE_FMT[] = "%a, %d %b %Y %H:%M:%S %z";
- ///////////////////////////////////////////////////////////////////////////////
- +// Cache for the secrets file, to avoid reading / loding them repeatedly on
- +// a reload of remap.config. This gets cached for 60s (not configurable).
- +//
- +class S3Config;
- +
- +class ConfigCache
- +{
- +public:
- + S3Config *get(const char *file);
- +
- +private:
- + std::unordered_map<std::string, std::pair<S3Config *, int>> _cache;
- + static const int _ttl = 60;
- +};
- +
- +ConfigCache gConfCache;
- +
- +///////////////////////////////////////////////////////////////////////////////
- // One configuration setup
- //
- int event_handler(TSCont, TSEvent, void *); // Forward declaration
- @@ -70,6 +92,26 @@ public:
- return _secret && (_secret_len > 0) && _keyid && (_keyid_len > 0) && (2 == _version);
- }
- + // Used to copy relevant configurations that can be configured in a config file
- + void
- + copy_from(const S3Config *src)
- + {
- + if (src->_secret) {
- + _secret = src->_secret;
- + _secret_len = src->_secret_len;
- + }
- +
- + if (src->_keyid) {
- + _keyid = src->_keyid;
- + _keyid_len = src->_keyid_len;
- + }
- +
- + // ToDo: this is a little odd, in that we'd overwrite something specified via getop parsing :/. Would
- + // need to know if the configuration file has modified these. But maybe that's an unusual use case...
- + _version = src->_version;
- + _virt_host = src->_virt_host;
- + }
- +
- // Getters
- bool
- virt_host() const
- @@ -124,7 +166,7 @@ public:
- }
- // Parse configs from an external file
- - bool parse_config(const char *config);
- + bool parse_config(const std::string &filename);
- // This should be called from the remap plugin, to setup the TXN hook for
- // SEND_REQUEST_HDR, such that we always attach the appropriate S3 auth.
- @@ -145,24 +187,17 @@ private:
- };
- bool
- -S3Config::parse_config(const char *config)
- +S3Config::parse_config(const std::string &filename)
- {
- - if (!config) {
- + if (0 == filename.size()) {
- TSError("[%s] called without a config file, this is broken", PLUGIN_NAME);
- return false;
- } else {
- - char filename[PATH_MAX + 1];
- -
- - if (*config != '/') {
- - snprintf(filename, sizeof(filename) - 1, "%s/%s", TSConfigDirGet(), config);
- - config = filename;
- - }
- -
- char line[512]; // These are long lines ...
- - FILE *file = fopen(config, "r");
- + FILE *file = fopen(filename.c_str(), "r");
- if (nullptr == file) {
- - TSError("[%s] unable to open %s", PLUGIN_NAME, config);
- + TSError("[%s] unable to open %s", PLUGIN_NAME, filename.c_str());
- return false;
- }
- @@ -209,6 +244,51 @@ S3Config::parse_config(const char *config)
- }
- ///////////////////////////////////////////////////////////////////////////////
- +// Implementation for the ConfigCache, it has to go here since we have a sort
- +// of circular dependency. Note that we always parse / get the configuration
- +// for the file, either from cache or by making one. The user of this just
- +// has to copy the relevant portions, but should not use the returned object
- +// directly (i.e. it must be copied).
- +//
- +S3Config *
- +ConfigCache::get(const char *file)
- +{
- + std::string filename;
- + struct timeval tv;
- +
- + gettimeofday(&tv, nullptr);
- +
- + // Make sure the filename is an absolute path, prepending the config dir if needed
- + if (*file != '/') {
- + filename = TSConfigDirGet();
- + filename += "/";
- + }
- + filename += filename;
- +
- + auto it = _cache.find(filename);
- +
- + if (it != _cache.end()) {
- + if (tv.tv_sec > (it->second.second + _ttl)) {
- + // Update the cached configuration file.
- + delete it->second.first;
- + it->second.first = new S3Config();
- + it->second.first->parse_config(filename);
- + }
- + return it->second.first;
- + } else {
- + // Create a new cached file.
- + S3Config *s3 = new S3Config();
- +
- + s3->parse_config(filename);
- + _cache[filename] = std::make_pair(s3, tv.tv_sec);
- +
- + return s3;
- + }
- +
- + TSAssert(!"Configuration parsing / caching failed");
- +}
- +
- +///////////////////////////////////////////////////////////////////////////////
- // This class is used to perform the S3 auth generation.
- //
- class S3Request
- @@ -541,7 +621,8 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char * /* errbuf ATS_UNUSE
- {nullptr, no_argument, nullptr, '\0'},
- };
- - S3Config *s3 = new S3Config();
- + S3Config *s3 = new S3Config();
- + S3Config *file_config = nullptr;
- // argv contains the "to" and "from" URLs. Skip the first so that the
- // second one poses as the program name.
- @@ -553,7 +634,7 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char * /* errbuf ATS_UNUSE
- switch (opt) {
- case 'c':
- - s3->parse_config(optarg);
- + file_config = gConfCache.get(optarg); // Get cached, or new, config object, from a file
- break;
- case 'a':
- s3->set_keyid(optarg);
- @@ -574,6 +655,11 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char * /* errbuf ATS_UNUSE
- }
- }
- + // Copy the config file secret into our instance of the configuration.
- + if (file_config) {
- + s3->copy_from(file_config);
- + }
- +
- // Make sure we got both the shared secret and the AWS secret
- if (!s3->valid()) {
- TSError("[%s] requires both shared and AWS secret configuration", PLUGIN_NAME);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement