XRootD
Loading...
Searching...
No Matches
XrdClS3Factory.hh
Go to the documentation of this file.
1/******************************************************************************/
2/* Copyright (C) 2025, Pelican Project, Morgridge Institute for Research */
3/* */
4/* This file is part of the XrdClS3 client plugin for XRootD. */
5/* */
6/* XRootD is free software: you can redistribute it and/or modify it under */
7/* the terms of the GNU Lesser General Public License as published by the */
8/* Free Software Foundation, either version 3 of the License, or (at your */
9/* option) any later version. */
10/* */
11/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
12/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
13/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
14/* License for more details. */
15/* */
16/* The copyright holder's institutional names and contributor's names may not */
17/* be used to endorse or promote products derived from this software without */
18/* specific prior written permission of the institution or contributor. */
19/******************************************************************************/
20
21#ifndef XRDCLS3_S3FACTORY_HH
22#define XRDCLS3_S3FACTORY_HH
23
25
26#include <mutex>
27#include <shared_mutex>
28#include <string>
29#include <string_view>
30
31namespace XrdCl {
32 class Log;
33}
34
35namespace XrdClS3 {
36
37const uint64_t kLogXrdClS3 = 73174;
38
39class Factory final : public XrdCl::PlugInFactory {
40public:
41 Factory();
42 virtual ~Factory() {}
43 Factory(const Factory &) = delete;
44
45 virtual XrdCl::FilePlugIn *CreateFile(const std::string &url) override;
46 virtual XrdCl::FileSystemPlugIn *CreateFileSystem(const std::string &url) override;
47
48 // Given a S3-style url (s3://bucket/object), return the corresponding HTTPS URL.
49 //
50 // If "obj_result" is not nullptr, then it will be set to the object/key and the resulting HTTPS URL
51 // will not include the key name.
52 static bool GenerateHttpUrl(const std::string &s3_url, std::string &https_url, std::string *obj_result, std::string &err_msg);
53
54 // Convenience function to extract the hostname from a URL.
55 static std::string_view ExtractHostname(const std::string_view url);
56
57 // Convenience function to trim the leading and trailing whitespace from a string.
58 static std::string_view TrimView(const std::string_view str);
59
60
61 // Generate a V4 signature for the given HTTP URL, returning the
62 // authorization token in auth_token. Returns true on success, false
63 // on failure, with an error message in err_msg.
64 static bool GenerateV4Signature(const std::string &url, const std::string &verb, std::vector<std::pair<std::string, std::string>> &headers, std::string &auth_token, std::string &err_msg);
65
66 // Given a HTTPS URL representing a S3 object request, return the bucket name.
67 //
68 // Parses the bucket name from the hostname (for virtual-hosted-style URLs) or
69 // from the path (for path-style URLs).
70 static std::string GetBucketFromHttpsUrl(const std::string &url);
71
72 // Given a bucket name, return the credentials to use.
73 static std::tuple<std::string, std::string, bool> GetCredentialsForBucket(const std::string &bucket, std::string &err_msg);
74
75 // Helper function to convert the URL to a canonical path form for V4 signing.
76 static std::string PathEncode(const std::string_view url);
77
78 // Helper function to remove XRootD-specific query parameters from an object name
79 static std::string CleanObjectName(const std::string &object);
80
81 static const std::string &GetMkdirSentinel() {return m_mkdir_sentinel;}
82
83 // Setters for the S3 endpoint, service, region, and URL style.
84 // Intended to be used for testing or configuration purposes.
85 static void SetEndpoint(const std::string &endpoint) { m_endpoint = endpoint; }
86 static void SetService(const std::string &service) { m_service = service; }
87 static void SetRegion(const std::string &region) { m_region = region; }
88 static void SetUrlStyle(const std::string &url_style) { m_url_style = url_style; }
89 static void SetDefaultCredentials(const std::string &access_key, const std::string &secret_key) {
90 m_default_creds.m_accesskey = access_key;
91 m_default_creds.m_secretkey = secret_key;
92 }
93 static void SetBucketCredentials(const std::string &bucket, const std::string &access_key, const std::string &secret_key) {
94 m_bucket_location_map[bucket] = {access_key, secret_key};
95 }
96 static void ResetCredCache() {
97 std::unique_lock lock(m_bucket_auth_map_mutex);
98 m_bucket_auth_map.clear();
99 }
100
101private:
102
103 // Iterate through the client configuration and determine the S3
104 // settings
105 static void InitS3Config();
106
107 // Helper function to canonicalize the query string for V4 signing.
108 static std::string CanonicalizeQueryString(const std::string &url);
109
110 static bool m_initialized;
111 static XrdCl::Log *m_log;
112 static std::once_flag m_init_once;
113
114 // Endpoint for the S3 service we will use
115 static std::string m_endpoint;
116 static std::string m_service;
117 static std::string m_region;
118 static std::string m_url_style;
119
120 // S3 doesn't have the concept of "directories"; if a given name
121 // (some/path) has an object containing it as a prefix
122 // (some/path/foo.txt), then we say it's a directory. Hence, to
123 // "make" a directory, we create a zero-length sentinel file inside
124 // it; this static variable controls the name.
125 static std::string m_mkdir_sentinel;
126
127 // Struct describing S3 credentials
128 struct Credentials {
129 std::string m_accesskey;
130 std::string m_secretkey;
131 };
132
133 // Default credentials if not specified for a bucket.
134 static Credentials m_default_creds;
135
136 // Map from bucket name to credentials to use
137 static std::unordered_map<std::string, Credentials> m_bucket_location_map;
138
139 // Shared mutex to protect access to the bucket credentials map.
140 static std::shared_mutex m_bucket_auth_map_mutex;
141
142 // Map for bucket-to-credential info.
143 static std::unordered_map<std::string, std::pair<Credentials, std::chrono::steady_clock::time_point>> m_bucket_auth_map;
144};
145
146}
147
148#endif // XRDCLS3_S3FACTORY_HH
static void ResetCredCache()
virtual XrdCl::FilePlugIn * CreateFile(const std::string &url) override
Create a file plug-in for the given URL.
static void SetBucketCredentials(const std::string &bucket, const std::string &access_key, const std::string &secret_key)
static std::string_view ExtractHostname(const std::string_view url)
static void SetEndpoint(const std::string &endpoint)
static std::string PathEncode(const std::string_view url)
static void SetRegion(const std::string &region)
static void SetDefaultCredentials(const std::string &access_key, const std::string &secret_key)
static std::string CleanObjectName(const std::string &object)
static bool GenerateHttpUrl(const std::string &s3_url, std::string &https_url, std::string *obj_result, std::string &err_msg)
virtual XrdCl::FileSystemPlugIn * CreateFileSystem(const std::string &url) override
Create a file system plug-in for the given URL.
static std::tuple< std::string, std::string, bool > GetCredentialsForBucket(const std::string &bucket, std::string &err_msg)
static void SetService(const std::string &service)
static bool GenerateV4Signature(const std::string &url, const std::string &verb, std::vector< std::pair< std::string, std::string > > &headers, std::string &auth_token, std::string &err_msg)
static std::string_view TrimView(const std::string_view str)
static const std::string & GetMkdirSentinel()
Factory(const Factory &)=delete
static void SetUrlStyle(const std::string &url_style)
static std::string GetBucketFromHttpsUrl(const std::string &url)
An interface for file plug-ins.
An interface for file plug-ins.
Handle diagnostics.
Definition XrdClLog.hh:101
const uint64_t kLogXrdClS3