XRootD
Loading...
Searching...
No Matches
XrdClS3::Factory Class Referencefinal

#include <XrdClS3Factory.hh>

Inheritance diagram for XrdClS3::Factory:
Collaboration diagram for XrdClS3::Factory:

Public Member Functions

 Factory ()
 Factory (const Factory &)=delete
virtual ~Factory ()
virtual XrdCl::FilePlugIn * CreateFile (const std::string &url) override
 Create a file plug-in for the given URL.
virtual XrdCl::FileSystemPlugIn * CreateFileSystem (const std::string &url) override
 Create a file system plug-in for the given URL.
Public Member Functions inherited from XrdCl::PlugInFactory
virtual ~PlugInFactory ()
 Destructor.

Static Public Member Functions

static std::string CleanObjectName (const std::string &object)
static std::string_view ExtractHostname (const std::string_view url)
static bool GenerateHttpUrl (const std::string &s3_url, std::string &https_url, std::string *obj_result, std::string &err_msg)
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 GetBucketFromHttpsUrl (const std::string &url)
static std::tuple< std::string, std::string, bool > GetCredentialsForBucket (const std::string &bucket, std::string &err_msg)
static const std::string & GetMkdirSentinel ()
static std::string PathEncode (const std::string_view url)
static void ResetCredCache ()
static void SetBucketCredentials (const std::string &bucket, const std::string &access_key, const std::string &secret_key)
static void SetDefaultCredentials (const std::string &access_key, const std::string &secret_key)
static void SetEndpoint (const std::string &endpoint)
static void SetRegion (const std::string &region)
static void SetService (const std::string &service)
static void SetUrlStyle (const std::string &url_style)
static std::string_view TrimView (const std::string_view str)

Detailed Description

Definition at line 39 of file XrdClS3Factory.hh.

Constructor & Destructor Documentation

◆ Factory() [1/2]

Factory::Factory ( )

Definition at line 85 of file XrdClS3Factory.cc.

85 {
86 std::call_once(m_init_once, [&] {
88 if (!m_log) {
89 return;
90 }
91 m_log->SetTopicName(kLogXrdClS3, "XrdClS3");
92
93 auto env = XrdCl::DefaultEnv::GetEnv();
94 if (!env) {
95 return;
96 }
97 InitS3Config();
98 m_initialized = true;
99 });
100}
static Log * GetLog()
Get default log.
static Env * GetEnv()
Get default client environment.
const uint64_t kLogXrdClS3

References Factory(), XrdCl::DefaultEnv::GetEnv(), XrdCl::DefaultEnv::GetLog(), and XrdClS3::kLogXrdClS3.

Referenced by Factory(), and Factory().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ~Factory()

virtual XrdClS3::Factory::~Factory ( )
inlinevirtual

Definition at line 42 of file XrdClS3Factory.hh.

42{}

◆ Factory() [2/2]

XrdClS3::Factory::Factory ( const Factory & )
delete

References Factory().

Here is the call graph for this function:

Member Function Documentation

◆ CleanObjectName()

std::string Factory::CleanObjectName ( const std::string & object)
static

Definition at line 293 of file XrdClS3Factory.cc.

293 {
294 std::string obj = input_obj;
295 auto loc = input_obj.find('?');
296 if (loc != std::string::npos) {
297 auto query = std::string_view(input_obj).substr(loc + 1);
298 obj = obj.substr(0, loc);
299 bool added_query = false;
300 while (!query.empty()) {
301 auto next_query_loc = query.find('&');
302 auto current_query = (next_query_loc == std::string::npos) ? query : query.substr(0, next_query_loc);
303 query = (next_query_loc == std::string::npos) ? "" : query.substr(next_query_loc + 1);
304 if (current_query.empty()) {
305 continue;
306 }
307 auto equal_loc = current_query.find('=');
308 if (equal_loc != std::string::npos) {
309 auto key = current_query.substr(0, equal_loc);
310 if (key != "authz") {
311 obj += (added_query ? "&" : "?") + std::string(current_query);
312 added_query = true;
313 }
314 } else if (current_query != "authz") {
315 obj += (added_query ? "&" : "?") + std::string(current_query);
316 added_query = true;
317 }
318 }
319 } else {
320 obj = input_obj;
321 }
322 return obj;
323}
if(ec< 0) ec

References CleanObjectName().

Referenced by CleanObjectName(), CreateFile(), GenerateHttpUrl(), XrdClS3::Filesystem::Locate(), XrdClS3::Filesystem::Query(), XrdClS3::Filesystem::Rm(), and XrdClS3::Filesystem::Stat().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ CreateFile()

virtual XrdCl::FilePlugIn * XrdClS3::Factory::CreateFile ( const std::string & url)
overridevirtual

Create a file plug-in for the given URL.

Implements XrdCl::PlugInFactory.

References CleanObjectName(), CreateFileSystem(), ExtractHostname(), GenerateHttpUrl(), GenerateV4Signature(), GetBucketFromHttpsUrl(), GetCredentialsForBucket(), PathEncode(), and TrimView().

Here is the call graph for this function:

◆ CreateFileSystem()

XrdCl::FileSystemPlugIn * Factory::CreateFileSystem ( const std::string & url)
overridevirtual

Create a file system plug-in for the given URL.

Implements XrdCl::PlugInFactory.

Definition at line 360 of file XrdClHttpFactory.cc.

360 {
361 Initialize();
362 if (!m_initialized) {return nullptr;}
363 return new Filesystem(url, m_queue, m_log);
364}
Filesystem(const std::string &, XrdCl::Log *log)

References CreateFileSystem().

Referenced by CreateFile(), and CreateFileSystem().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ExtractHostname()

std::string_view Factory::ExtractHostname ( const std::string_view url)
static

Definition at line 326 of file XrdClS3Factory.cc.

326 {
327 auto loc = url.find("://");
328 if (loc == std::string_view::npos) {
329 return {};
330 }
331 loc += 3; // Move past "://"
332 auto slash_loc = url.find('/', loc);
333 auto query_loc = url.find('?', loc);
334 if (query_loc != std::string_view::npos && (slash_loc == std::string_view::npos || query_loc < slash_loc)) {
335 slash_loc = query_loc; // If there's a query, we stop at it
336 }
337 auto authority = url.substr(loc, slash_loc - loc);
338 if (authority.empty()) {
339 return {};
340 }
341 auto at_loc = authority.find('@');
342 if (at_loc != std::string_view::npos) {
343 // If there's an '@', we have user info, so we skip it
344 authority = authority.substr(at_loc + 1);
345 }
346 // If the authority contains a port, we need to strip it
347 auto colon_loc = authority.find(':');
348 if (colon_loc != std::string_view::npos) {
349 authority = authority.substr(0, colon_loc);
350 }
351 return authority;
352}

References ExtractHostname().

Referenced by CreateFile(), ExtractHostname(), GenerateHttpUrl(), GenerateV4Signature(), and GetBucketFromHttpsUrl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GenerateHttpUrl()

bool Factory::GenerateHttpUrl ( const std::string & s3_url,
std::string & https_url,
std::string * obj_result,
std::string & err_msg )
static

Definition at line 413 of file XrdClS3Factory.cc.

413 {
414 if (s3_url.substr(0, 5) != "s3://") {
415 err_msg = "Provided URL does not start with s3://";
416 return false;
417 }
418 auto loc = s3_url.find('/', 5);
419 auto bucket = s3_url.substr(5, loc - 5);
420 auto at_loc = bucket.find('@');
421 if (at_loc != std::string::npos) {
422 std::string login = "";
423 login = bucket.substr(0, at_loc);
424 bucket = bucket.substr(at_loc + 1);
425 }
426 std::string endpoint = m_endpoint;
427 std::string region = m_region;
428 if ((bucket == m_endpoint) || m_endpoint.empty()) {
429 endpoint = bucket;
430 auto old_loc = loc + 1;
431 loc = s3_url.find('/', loc + 1);
432 if (loc == std::string::npos) {
433 err_msg = "Provided S3 URL does not contain a bucket in path";
434 return false;
435 }
436 bucket = s3_url.substr(old_loc, loc - old_loc);
437 } else {
438 auto authority = ExtractHostname(s3_url);
439 std::string test_endpoint = "." + endpoint;
440 if (!m_region.empty()) {
441 auto bucket_loc = authority.rfind("." + m_region + test_endpoint);
442 if (bucket_loc != std::string::npos) {
443 bucket = authority.substr(0, bucket_loc);
444 } else {
445 auto bucket_loc = authority.rfind(test_endpoint);
446 if (bucket_loc != std::string::npos) {
447 bucket = authority.substr(0, bucket_loc);
448 }
449 }
450 } else {
451 auto bucket_loc = authority.rfind(test_endpoint);
452 if (bucket_loc != std::string::npos) {
453 bucket = authority.substr(0, bucket_loc);
454 }
455 }
456 }
457 std::string obj;
458 if (loc != std::string::npos) {
459 obj = s3_url.substr(loc + 1);
460 }
461 // Strip out "authz" query parameters; those are internal to XRootD.
462 obj = CleanObjectName(obj);
463 if (obj_result) {
464 *obj_result = obj;
465 }
466 if (m_url_style == "virtual" || m_url_style.empty()) {
467 https_url = "https://" + bucket + "." + m_region + "." + endpoint + (obj_result ? "" : ("/" + obj));
468 return true;
469 } else if (m_url_style == "path") {
470 if (!m_region.empty()) {
471 https_url = "https://" + m_region + "." + endpoint + "/" + bucket + (obj_result ? "" : ("/" + obj));
472 } else {
473 https_url = "https://" + endpoint + "/" + bucket + (obj_result ? "" : ("/" + obj));
474 }
475 return true;
476 } else {
477 err_msg = "Server configuration has invalid setting for URL style";
478 return false;
479 }
480}
static std::string_view ExtractHostname(const std::string_view url)
static std::string CleanObjectName(const std::string &object)

References CleanObjectName(), ExtractHostname(), and GenerateHttpUrl().

Referenced by CreateFile(), XrdClS3::Filesystem::DirList(), GenerateHttpUrl(), and XrdClS3::Filesystem::MkDir().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GenerateV4Signature()

bool Factory::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

Definition at line 483 of file XrdClS3Factory.cc.

483 {
484 auto bucket = GetBucketFromHttpsUrl(url);
485
486 // If we're using temporary credentials, we need to add the token
487 // header here as well. We set saKey and keyID here (well before
488 // necessary) since we'll get them for free when we get the token.
489 auto [keyId, secretKey, ok] = GetCredentialsForBucket(bucket, err_msg);
490 if (!ok) {
491 return false;
492 }
493
494 if (secretKey.empty()) {
495 auth_token = "";
496 return true;
497 }
498
499 //
500 // Create task 1's inputs.
501 //
502
503 auto canonicalURI = PathEncode(url);
504
505 // The canonical query string is the alphabetically sorted list of
506 // URI-encoded parameter names '=' values, separated by '&'s.
507 auto canonicalQueryString = CanonicalizeQueryString(url);
508
509 // The canonical headers must include the Host header, so add that
510 // now if we don't have it.
511 if (std::find_if(headers.begin(), headers.end(),
512 [](const auto &pair) { return pair.first == "Host"; }) == headers.end()) {
513 auto host = ExtractHostname(url);
514 if (host.empty()) {
515 err_msg = "Unable to extract hostname from URL: " + url;
516 return false;
517 }
518 headers.emplace_back("Host", host);
519 }
520
521 // S3 complains if x-amz-date isn't signed, so do this early.
522 auto iter = std::find_if(headers.begin(), headers.end(),
523 [](const auto &pair) { return !strcasecmp(pair.first.c_str(), "X-Amz-Date"); });
524 std::string date_time;
525 char date_char[] = "YYYYMMDD";
526 if (iter == headers.end()) {
527 time_t now;
528 time(&now);
529 struct tm brokenDownTime;
530 gmtime_r(&now, &brokenDownTime);
531
532 date_time = "YYYYMMDDThhmmssZ";
533 strftime(date_time.data(), date_time.size(), "%Y%m%dT%H%M%SZ", &brokenDownTime);
534 headers.emplace_back("X-Amz-Date", date_time);
535 strftime(date_char, sizeof(date_char), "%Y%m%d", &brokenDownTime);
536 } else {
537 date_time = iter->second;
538 auto loc = date_time.find('T', 0);
539 if (loc != 8) {
540 err_msg = "Invalid value for X-Amz-Date";
541 return false;
542 }
543 memcpy(date_char, date_time.c_str(), 8);
544 }
545
546 // The canonical payload hash is the lowercase hexadecimal string of the
547 // (SHA256) hash value of the payload or "UNSIGNED-PAYLOAD" if
548 // we are not signing the payload.
549 std::string payload_hash = "UNSIGNED-PAYLOAD";
550 iter = std::find_if(headers.begin(), headers.end(),
551 [](const auto &pair) { return !strcasecmp(pair.first.c_str(), "X-Amz-Content-Sha256"); });
552 if (iter == headers.end()) {
553 headers.emplace_back("X-Amz-Content-Sha256", payload_hash);
554 } else {
555 payload_hash = iter->second;
556 }
557
558 // The canonical list of headers is a sorted list of lowercase header
559 // names paired via ':' with the trimmed header value, each pair
560 // terminated with a newline.
561 std::vector<std::pair<std::string, std::string>> transformed_headers;
562 transformed_headers.reserve(headers.size());
563 for (const auto &info : headers) {
564 std::string header = info.first;
565 std::transform(header.begin(), header.end(), header.begin(), &tolower);
566
567 std::string value = info.second;
568 if (value.empty()) {
569 continue;
570 }
571 auto value_trimmed = std::string(TrimView(value));
572
573 // Convert internal runs of spaces into single spaces.
574 unsigned left = 1;
575 unsigned right = 1;
576 bool inSpaces = false;
577 while (right < value_trimmed.length()) {
578 if (!inSpaces) {
579 if (value_trimmed[right] == ' ') {
580 inSpaces = true;
581 left = right;
582 ++right;
583 } else {
584 ++right;
585 }
586 } else {
587 if (value_trimmed[right] == ' ') {
588 ++right;
589 } else {
590 inSpaces = false;
591 value_trimmed.erase(left, right - left - 1);
592 right = left + 1;
593 }
594 }
595 }
596
597 transformed_headers.emplace_back(header, value);
598 }
599 std::sort(transformed_headers.begin(), transformed_headers.end(),
600 [](const auto &a, const auto &b) { return a.first < b.first; });
601
602 // The canonical list of signed headers is trivial to generate while
603 // generating the list of headers.
604 std::string signedHeaders, canonicalHeaders;
605 for (const auto &info : transformed_headers) {
606 canonicalHeaders += info.first + ":" + info.second + "\n";
607 signedHeaders += info.first + ";";
608 }
609 signedHeaders.erase(signedHeaders.end() - 1);
610
611 // Task 1: create the canonical request.
612 auto canonicalRequest =
613 verb + "\n" + canonicalURI + "\n" + canonicalQueryString + "\n" +
614 canonicalHeaders + "\n" + signedHeaders + "\n" + payload_hash;
615
616 //
617 // Create task 2's inputs.
618 //
619
620 // Hash the canonical request the way we did the payload.
621 std::string canonicalRequestHash;
622 std::vector<unsigned char> messageDigest;
623 messageDigest.resize(EVP_MAX_MD_SIZE);
624 if (!ComputeSHA256(canonicalRequest, messageDigest)) {
625 err_msg = "Unable to hash canonical request.";
626 return false;
627 }
628 MessageDigestAsHex(messageDigest, canonicalRequestHash);
629
630 // Task 2: create the string to sign.
631 auto credentialScope = std::string(date_char) + "/" + m_region + "/" + m_service + "/aws4_request";
632 auto stringToSign = std::string("AWS4-HMAC-SHA256\n") + date_time + "\n" + credentialScope + "\n" + canonicalRequestHash;
633
634 //
635 // Creating task 3's inputs was done when we checked to see if we needed
636 // to get the security token, since they come along for free when we do.
637 //
638
639 // Task 3: calculate the signature.
640 auto saKey = std::string("AWS4") + secretKey;
641 unsigned int mdLength = 0;
642 const unsigned char *hmac =
643 HMAC(EVP_sha256(), saKey.c_str(), saKey.length(), (unsigned char *)date_char,
644 sizeof(date_char) - 1, messageDigest.data(), &mdLength);
645 if (hmac == NULL) {
646 err_msg = "Unable to calculate HMAC for date.";
647 return false;
648 }
649
650 unsigned int md2Length = 0;
651 unsigned char messageDigest2[EVP_MAX_MD_SIZE];
652 hmac = HMAC(EVP_sha256(), messageDigest.data(), mdLength,
653 reinterpret_cast<unsigned char *>(m_region.data()), m_region.size(), messageDigest2,
654 &md2Length);
655 if (hmac == NULL) {
656 err_msg = "Unable to calculate HMAC for region.";
657 return false;
658 }
659
660 hmac = HMAC(EVP_sha256(), messageDigest2, md2Length,
661 reinterpret_cast<unsigned char *>(m_service.data()), m_service.size(), messageDigest.data(),
662 &mdLength);
663 if (hmac == NULL) {
664 err_msg = "Unable to calculate HMAC for service.";
665 return false;
666 }
667
668 const char request_char[] = "aws4_request";
669 hmac = HMAC(EVP_sha256(), messageDigest.data(), messageDigest.size(), reinterpret_cast<const unsigned char *>(request_char),
670 sizeof(request_char) - 1, messageDigest2, &md2Length);
671 if (hmac == NULL) {
672 err_msg = "Unable to calculate HMAC for request.";
673 return false;
674 }
675
676 hmac = HMAC(EVP_sha256(), messageDigest2, md2Length,
677 reinterpret_cast<unsigned char *>(stringToSign.data()),
678 stringToSign.size(), messageDigest.data(), &mdLength);
679 if (hmac == NULL) {
680 err_msg = "Unable to calculate HMAC for request string.";
681 return false;
682 }
683
684 std::string signature;
685 MessageDigestAsHex(messageDigest, signature);
686
687 auth_token =
688 std::string("AWS4-HMAC-SHA256 Credential=") + keyId + "/" + credentialScope +
689 ",SignedHeaders=" + signedHeaders + ",Signature=" + signature;
690 return true;
691}
static std::string PathEncode(const std::string_view url)
static std::tuple< std::string, std::string, bool > GetCredentialsForBucket(const std::string &bucket, std::string &err_msg)
static std::string_view TrimView(const std::string_view str)
static std::string GetBucketFromHttpsUrl(const std::string &url)

References ExtractHostname(), GenerateV4Signature(), GetBucketFromHttpsUrl(), GetCredentialsForBucket(), PathEncode(), and TrimView().

Referenced by CreateFile(), and GenerateV4Signature().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetBucketFromHttpsUrl()

std::string Factory::GetBucketFromHttpsUrl ( const std::string & url)
static

Definition at line 694 of file XrdClS3Factory.cc.

694 {
695 if (m_url_style == "virtual" || m_url_style.empty()) {
696 // Virtual-hosted-style URLs are of the form https://bucket.region.endpoint/object
697 auto hostname = ExtractHostname(url);
698 if (hostname.empty()) {
699 return {};
700 }
701 auto test_endpoint = "." + m_endpoint;
702 if (!m_region.empty()) test_endpoint = "." + m_region + test_endpoint;
703 auto loc = hostname.rfind(test_endpoint);
704 if (loc == std::string::npos) {
705 if (!m_region.empty()) {
706 loc = hostname.rfind("." + m_endpoint);
707 if (loc != std::string::npos) {
708 return std::string(hostname.substr(0, loc));
709 }
710 }
711 return {};
712 }
713 return std::string(hostname.substr(0, loc));
714 } else if (m_url_style == "path") {
715 // Path style URLs are of the form https://region.endpoint/bucket/object
716 auto loc = url.find("://");
717 if (loc == std::string::npos) {
718 return {};
719 }
720 loc += 3; // Move past "://"
721 auto slash_loc = url.find('/', loc);
722 if (slash_loc == std::string::npos) {
723 return {};
724 }
725 auto bucket_start = slash_loc + 1;
726 auto bucket_end = url.find('/', bucket_start);
727 if (bucket_end == std::string::npos) {
728 return url.substr(bucket_start);
729 }
730 return url.substr(bucket_start, bucket_end - bucket_start);
731 } else {
732 // Invalid URL style
733 return {};
734 }
735}

References ExtractHostname(), and GetBucketFromHttpsUrl().

Referenced by CreateFile(), GenerateV4Signature(), and GetBucketFromHttpsUrl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetCredentialsForBucket()

std::tuple< std::string, std::string, bool > Factory::GetCredentialsForBucket ( const std::string & bucket,
std::string & err_msg )
static

Definition at line 738 of file XrdClS3Factory.cc.

739{
740 auto now = std::chrono::steady_clock::now();
741 {
742 std::shared_lock lock(m_bucket_auth_map_mutex);
743 auto iter = m_bucket_auth_map.find(bucket);
744 if (iter != m_bucket_auth_map.end()) {
745 // If we have credentials for this bucket, check if they are still valid.
746 auto &creds = iter->second.first;
747 auto &expiration = iter->second.second;
748 if (now < expiration) {
749 // Credentials are still valid, return them.
750 return {creds.m_accesskey, creds.m_secretkey, true};
751 }
752 }
753 }
754
755 std::unique_lock lock(m_bucket_auth_map_mutex);
756 auto iter = m_bucket_location_map.find(bucket);
757 std::string access_key_location, secret_key_location;
758 if (iter == m_bucket_location_map.end()) {
759 // If we don't have credentials for this bucket, use the default.
760 if (m_default_creds.m_accesskey.empty() || m_default_creds.m_secretkey.empty()) {
761 // No credentials at all, so we assume public access.
762 m_bucket_auth_map[bucket] = {{"", ""}, now + std::chrono::minutes(1)};
763 return {"", "", true};
764 }
765 access_key_location = m_default_creds.m_accesskey;
766 secret_key_location = m_default_creds.m_secretkey;
767 } else {
768 access_key_location = iter->second.m_accesskey;
769 secret_key_location = iter->second.m_secretkey;
770 }
771 if (access_key_location.empty() && secret_key_location.empty()) {
772 // If both are empty, we assume public access.
773 m_bucket_auth_map[bucket] = {{"", ""}, now + std::chrono::minutes(1)};
774 return {"", "", true};
775 }
776 if (access_key_location.empty() || secret_key_location.empty()) {
777 err_msg = "No credentials available for bucket: " + bucket;
778 m_bucket_auth_map[bucket] = {{"", ""}, now + std::chrono::seconds(10)};
779 return {"", "", false};
780 }
781
782 std::string access_key, secret_key;
783 if (!ReadShortFile(access_key_location, access_key, err_msg)) {
784 m_bucket_auth_map[bucket] = {{"", ""}, now + std::chrono::seconds(10)};
785 return {"", "", false};
786 }
787 access_key = TrimView(access_key);
788
789 if (!ReadShortFile(secret_key_location, secret_key, err_msg)) {
790 m_bucket_auth_map[bucket] = {{"", ""}, now + std::chrono::seconds(10)};
791 return {"", "", false};
792 }
793 secret_key = TrimView(secret_key);
794
795 if (access_key.empty() || secret_key.empty()) {
796 err_msg = "Credentials for bucket '" + bucket + "' are empty.";
797 m_bucket_auth_map[bucket] = {{"", ""}, now + std::chrono::seconds(10)};
798 return {"", "", false};
799 }
800 m_bucket_auth_map[bucket] = {{access_key, secret_key}, now + std::chrono::minutes(1)};
801 return {access_key, secret_key, true};
802}

References GetCredentialsForBucket(), and TrimView().

Referenced by CreateFile(), GenerateV4Signature(), and GetCredentialsForBucket().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetMkdirSentinel()

const std::string & XrdClS3::Factory::GetMkdirSentinel ( )
inlinestatic

Definition at line 81 of file XrdClS3Factory.hh.

81{return m_mkdir_sentinel;}

Referenced by XrdClS3::Filesystem::MkDir(), and XrdClS3::Filesystem::RmDir().

Here is the caller graph for this function:

◆ PathEncode()

std::string Factory::PathEncode ( const std::string_view url)
static

Definition at line 805 of file XrdClS3Factory.cc.

805 {
806 auto loc = url.find("://");
807 if (loc == std::string_view::npos) {
808 return "";
809 }
810 auto path_loc = url.find("/", loc + 3);
811 auto query_loc = url.find("?", loc + 3);
812 if (query_loc != std::string_view::npos && (path_loc == std::string_view::npos || query_loc < path_loc)) {
813 // No path, just a query string
814 return "/";
815 }
816 auto path = url.substr(path_loc, query_loc - path_loc);
817 std::string segment;
818 std::string encoded;
819
820 size_t next = 0;
821 size_t offset = 0;
822 const auto length = path.size();
823 while (offset < length) {
824 next = strcspn(path.data() + offset, "/");
825 if (next == 0) {
826 encoded += "/";
827 offset += 1;
828 continue;
829 }
830 if (offset + next >= length) {
831 next = length - offset;
832 }
833
834 segment = std::string(path.data() + offset, next);
835 encoded += AmazonURLEncode(segment);
836
837 offset += next;
838 }
839 return encoded;
840}

References PathEncode().

Referenced by CreateFile(), GenerateV4Signature(), and PathEncode().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ResetCredCache()

void XrdClS3::Factory::ResetCredCache ( )
inlinestatic

Definition at line 96 of file XrdClS3Factory.hh.

96 {
97 std::unique_lock lock(m_bucket_auth_map_mutex);
98 m_bucket_auth_map.clear();
99 }

◆ SetBucketCredentials()

void XrdClS3::Factory::SetBucketCredentials ( const std::string & bucket,
const std::string & access_key,
const std::string & secret_key )
inlinestatic

Definition at line 93 of file XrdClS3Factory.hh.

93 {
94 m_bucket_location_map[bucket] = {access_key, secret_key};
95 }

◆ SetDefaultCredentials()

void XrdClS3::Factory::SetDefaultCredentials ( const std::string & access_key,
const std::string & secret_key )
inlinestatic

Definition at line 89 of file XrdClS3Factory.hh.

89 {
90 m_default_creds.m_accesskey = access_key;
91 m_default_creds.m_secretkey = secret_key;
92 }

◆ SetEndpoint()

void XrdClS3::Factory::SetEndpoint ( const std::string & endpoint)
inlinestatic

Definition at line 85 of file XrdClS3Factory.hh.

85{ m_endpoint = endpoint; }

◆ SetRegion()

void XrdClS3::Factory::SetRegion ( const std::string & region)
inlinestatic

Definition at line 87 of file XrdClS3Factory.hh.

87{ m_region = region; }

◆ SetService()

void XrdClS3::Factory::SetService ( const std::string & service)
inlinestatic

Definition at line 86 of file XrdClS3Factory.hh.

86{ m_service = service; }

◆ SetUrlStyle()

void XrdClS3::Factory::SetUrlStyle ( const std::string & url_style)
inlinestatic

Definition at line 88 of file XrdClS3Factory.hh.

88{ m_url_style = url_style; }

◆ TrimView()

std::string_view Factory::TrimView ( const std::string_view str)
static

Definition at line 844 of file XrdClS3Factory.cc.

844 {
845 auto view = ltrim_view(input_view);
846 for (size_t idx = 0; idx < input_view.size(); idx++) {
847 if (!isspace(view[view.size() - 1 - idx])) {
848 return view.substr(0, view.size() - idx);
849 }
850 }
851 return "";
852}
std::string_view ltrim_view(const std::string_view &input_view)

References TrimView().

Referenced by CreateFile(), GenerateV4Signature(), GetCredentialsForBucket(), and TrimView().

Here is the call graph for this function:
Here is the caller graph for this function:

The documentation for this class was generated from the following files: