From b8205c1d460e70723e3e9c0e7b89aacbd1c462d2 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Sat, 16 Mar 2024 22:01:08 -0500 Subject: [PATCH] Make the prefix used more generic Do not force the HTTP plugin to have a prefix that starts with the hostname. Instead, make it so you can cut an arbitrary prefix off the incoming path and prepend it with an arbitrary URL base. --- src/HTTPFile.cc | 42 +++++++++++++++++++++++++++++------------- src/HTTPFileSystem.cc | 28 +++++++++++++++++----------- src/HTTPFileSystem.hh | 8 ++++++-- 3 files changed, 52 insertions(+), 26 deletions(-) diff --git a/src/HTTPFile.cc b/src/HTTPFile.cc index 4b5d701..8beb948 100644 --- a/src/HTTPFile.cc +++ b/src/HTTPFile.cc @@ -52,31 +52,42 @@ HTTPFile::HTTPFile(XrdSysError &log, HTTPFileSystem *oss) : last_modified(0) {} +// Ensures that path is of the form /storagePrefix/object and returns +// the resulting object value. The storagePrefix does not necessarily begin +// with '/' +// +// Examples: +// /foo/bar, /foo/bar/baz -> baz +// storage.com/foo, /storage.com/foo/bar -> bar +// /baz, /foo/bar -> error int -parse_path( const std::string & hname, const char * path, std::string & object ) { - const std::filesystem::path p(path); - const std::filesystem::path h(hname); +parse_path(const std::string &storagePrefixStr, const char *pathStr, std::string &object) { + const std::filesystem::path storagePath(pathStr); + const std::filesystem::path storagePrefix(storagePrefixStr); - auto prefixComponents = h.begin(); - auto pathComponents = p.begin(); + auto prefixComponents = storagePrefix.begin(); + auto pathComponents = storagePath.begin(); std::filesystem::path full; std::filesystem::path prefix; - pathComponents++; // The path will begin with '/' while the hostname will not. Skip the first slash for comparison + pathComponents++; + if (!storagePrefixStr.empty() && storagePrefixStr[0] == '/') { + prefixComponents++; + } - while (prefixComponents != h.end() && *prefixComponents == *pathComponents ) { + while (prefixComponents != storagePrefix.end() && *prefixComponents == *pathComponents ) { full /= *prefixComponents++; prefix /= *pathComponents++; } // Check that nothing diverged before reaching end of service name - if (prefixComponents != h.end()) { + if (prefixComponents != storagePrefix.end()) { return -ENOENT; } std::filesystem::path obj_path; - while (pathComponents != p.end()) { + while (pathComponents != storagePath.end()) { obj_path /= *pathComponents++; } @@ -90,12 +101,17 @@ HTTPFile::Open(const char *path, int Oflag, mode_t Mode, XrdOucEnv &env) { auto configured_hostname = m_oss->getHTTPHostName(); auto configured_hostUrl = m_oss->getHTTPHostUrl(); + const auto &configured_url_base = m_oss->getHTTPUrlBase(); + if (!configured_url_base.empty()) { + configured_hostUrl = configured_url_base; + configured_hostname = m_oss->getStoragePrefix(); + } // // Check the path for validity. // std::string object; - int rv = parse_path( configured_hostname, path, object ); + int rv = parse_path(configured_hostname, path, object); if( rv != 0 ) { return rv; } @@ -136,10 +152,10 @@ HTTPFile::Read(void *buffer, off_t offset, size_t size) int HTTPFile::Fstat(struct stat *buff) { - m_log.Log(LogMask::Debug, "HTTPFile::Fstat", "About to perform HTTPFile::Fstat(): hostname / object", hostname.c_str(), object.c_str()); + m_log.Log(LogMask::Debug, "HTTPFile::Fstat", "About to perform HTTPFile::Fstat():", hostUrl.c_str(), object.c_str()); HTTPHead head( - this->hostUrl, - this->object, + hostUrl, + object, m_log ); diff --git a/src/HTTPFileSystem.cc b/src/HTTPFileSystem.cc index 404b035..979d8ed 100644 --- a/src/HTTPFileSystem.cc +++ b/src/HTTPFileSystem.cc @@ -108,19 +108,25 @@ HTTPFileSystem::Config(XrdSysLogger *lp, const char *configfn) if(! temporary) { continue; } value = temporary; - if(! handle_required_config( attribute, "httpserver.host_name", - value, this->http_host_name ) ) { Config.Close(); return false; } - if(! handle_required_config( attribute, "httpserver.host_url", - value, this->http_host_url ) ) { Config.Close(); return false; } + if (!handle_required_config(attribute, "httpserver.host_name", value, http_host_name) || + !handle_required_config(attribute, "httpserver.host_url", value, http_host_url) || + !handle_required_config(attribute, "httpserver.url_base", value, m_url_base) || + !handle_required_config(attribute, "httpserver.storage_prefix", value, m_storage_prefix)) + { + Config.Close(); + return false; + } } - if( this->http_host_name.empty() ) { - m_log.Emsg("Config", "httpserver.host_name not specified"); - return false; - } - if( this->http_host_url.empty() ) { - m_log.Emsg("Config", "httpserver.host_url not specified"); - return false; + if (m_url_base.empty()) { + if (http_host_name.empty()) { + m_log.Emsg("Config", "httpserver.host_name not specified; this or httpserver.url_base are required"); + return false; + } + if (http_host_url.empty()) { + m_log.Emsg("Config", "httpserver.host_url not specified; this or httpserver.url_base are required"); + return false; + } } int retc = Config.LastError(); diff --git a/src/HTTPFileSystem.hh b/src/HTTPFileSystem.hh index 2c7e77e..6d19134 100644 --- a/src/HTTPFileSystem.hh +++ b/src/HTTPFileSystem.hh @@ -75,8 +75,10 @@ public: int Lfn2Pfn(const char *Path, char *buff, int blen) {return -ENOSYS;} const char *Lfn2Pfn(const char *Path, char *buff, int blen, int &rc) {return nullptr;} - const std::string & getHTTPHostName() const { return http_host_name; } - const std::string & getHTTPHostUrl() const { return http_host_url; } + const std::string &getHTTPHostName() const {return http_host_name;} + const std::string &getHTTPHostUrl() const {return http_host_url;} + const std::string &getHTTPUrlBase() const {return m_url_base;} + const std::string &getStoragePrefix() const {return m_storage_prefix;} protected: XrdOucEnv *m_env; @@ -92,4 +94,6 @@ protected: private: std::string http_host_name; std::string http_host_url; + std::string m_url_base; + std::string m_storage_prefix; };