XRootD
XrdHttpChecksumHandler.cc
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
2 // This file is part of XrdHTTP: A pragmatic implementation of the
3 // HTTP/WebDAV protocol for the Xrootd framework
4 //
5 // Copyright (c) 2013 by European Organization for Nuclear Research (CERN)
6 // Author: Cedric Caffy <ccaffy@cern.ch>
7 // File Date: Mar 2023
8 //------------------------------------------------------------------------------
9 // XRootD is free software: you can redistribute it and/or modify
10 // it under the terms of the GNU Lesser General Public License as published by
11 // the Free Software Foundation, either version 3 of the License, or
12 // (at your option) any later version.
13 //
14 // XRootD is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public License
20 // along with XRootD. If not, see <http://www.gnu.org/licenses/>.
21 //------------------------------------------------------------------------------
22 
24 #include "XrdOuc/XrdOucTUtils.hh"
25 #include "XrdOuc/XrdOucUtils.hh"
26 #include <exception>
27 #include <algorithm>
28 
29 std::map<std::string,XrdHttpChecksumHandlerImpl::XrdHttpChecksumPtr> XrdHttpChecksumHandlerImpl::XROOTD_DIGEST_NAME_TO_CKSUMS;
30 
31 void XrdHttpChecksumHandlerImpl::initializeCksumsMaps() {
32  addChecksumToMaps(std::make_unique<XrdHttpChecksum>("md5","md5",true));
33  addChecksumToMaps(std::make_unique<XrdHttpChecksum>("adler32","adler32",false));
34  addChecksumToMaps(std::make_unique<XrdHttpChecksum>("sha1","sha",true));
35  addChecksumToMaps(std::make_unique<XrdHttpChecksum>("sha256","sha-256",true));
36  addChecksumToMaps(std::make_unique<XrdHttpChecksum>("sha512","sha-512",true));
37  addChecksumToMaps(std::make_unique<XrdHttpChecksum>("cksum","UNIXcksum",false));
38  addChecksumToMaps(std::make_unique<XrdHttpChecksum>("crc32","crc32",false));
39  addChecksumToMaps(std::make_unique<XrdHttpChecksum>("crc32c","crc32c",true));
40 }
41 
42 void XrdHttpChecksumHandlerImpl::addChecksumToMaps(XrdHttpChecksumHandlerImpl::XrdHttpChecksumPtr && checksum) {
43  // We also map xrootd-configured checksum's HTTP names to the corresponding checksums --> this will allow
44  // users to configure algorithms like, for example, `sha-512` and be considered as `sha512` algorithm
45  XROOTD_DIGEST_NAME_TO_CKSUMS[checksum->getHttpNameLowerCase()] = std::make_unique<XrdHttpChecksum>(checksum->getHttpNameLowerCase(), checksum->getHttpName(), checksum->needsBase64Padding());
46  XROOTD_DIGEST_NAME_TO_CKSUMS[checksum->getXRootDConfigDigestName()] = std::move(checksum);
47 }
48 
50  if(!mConfiguredChecksums.empty()) {
51  std::vector<std::string> userDigests = getUserDigests(userDigestIn);
52  //Loop over the user digests and find the corresponding checksum
53  for(auto userDigest: userDigests) {
54  auto httpCksum = std::find_if(mConfiguredChecksums.begin(), mConfiguredChecksums.end(),[userDigest](const XrdHttpChecksumRawPtr & cksum){
55  return userDigest == cksum->getHttpNameLowerCase();
56  });
57  if(httpCksum != mConfiguredChecksums.end()) {
58  return *httpCksum;
59  }
60  }
61  return mConfiguredChecksums[0];
62  }
63  //If there are no configured checksums, return nullptr
64  return nullptr;
65 }
66 
67 const std::vector<std::string> &XrdHttpChecksumHandlerImpl::getNonIANAConfiguredCksums() const {
68  return mNonIANAConfiguredChecksums;
69 }
70 
71 const std::vector<XrdHttpChecksumHandler::XrdHttpChecksumRawPtr> & XrdHttpChecksumHandlerImpl::getConfiguredChecksums() const {
72  return mConfiguredChecksums;
73 }
74 
75 
76 void XrdHttpChecksumHandlerImpl::configure(const char *csList) {
77  initializeCksumsMaps();
78  if(csList != nullptr) {
79  initializeXRootDConfiguredCksums(csList);
80  }
81 }
82 
83 void XrdHttpChecksumHandlerImpl::initializeXRootDConfiguredCksums(const char *csList) {
84  std::vector<std::string> splittedCslist;
85  XrdOucTUtils::splitString(splittedCslist,csList,",");
86  for(auto csElt: splittedCslist) {
87  auto csName = getElement(csElt,":",1);
88  auto checksumItor = XROOTD_DIGEST_NAME_TO_CKSUMS.find(csName);
89  if(checksumItor != XROOTD_DIGEST_NAME_TO_CKSUMS.end()) {
90  mConfiguredChecksums.push_back(checksumItor->second.get());
91  } else {
92  mNonIANAConfiguredChecksums.push_back(csName);
93  }
94  }
95 }
96 
97 std::string XrdHttpChecksumHandlerImpl::getElement(const std::string &input, const std::string & delimiter,
98  const size_t position) {
99  std::vector<std::string> elementsAfterSplit;
100  XrdOucTUtils::splitString(elementsAfterSplit,input,delimiter);
101  return elementsAfterSplit[position];
102 }
103 
104 std::vector<std::string> XrdHttpChecksumHandlerImpl::getUserDigests(const std::string &userDigests) {
105  //userDigest is a comma-separated list with q-values
106  std::vector<std::string> userDigestsRet;
107  std::vector<std::string> userDigestsWithQValues;
108  XrdOucTUtils::splitString(userDigestsWithQValues,userDigests,",");
109  for(auto & userDigestWithQValue: userDigestsWithQValues){
110  std::transform(userDigestWithQValue.begin(),userDigestWithQValue.end(),userDigestWithQValue.begin(),::tolower);
111  auto userDigest = getElement(userDigestWithQValue,";",0);
112  XrdOucUtils::trim(userDigest);
113  userDigestsRet.push_back(userDigest);
114  }
115  return userDigestsRet;
116 }
const std::vector< std::string > & getNonIANAConfiguredCksums() const
std::unique_ptr< XrdHttpChecksum > XrdHttpChecksumPtr
XrdHttpChecksumRawPtr getChecksumToRun(const std::string &userDigest) const
void configure(const char *csList)
const std::vector< XrdHttpChecksumRawPtr > & getConfiguredChecksums() const
static void splitString(Container &result, const std::string &input, const std::string &delimiter)
Split a string.
Definition: XrdOucTUtils.hh:51
static void trim(std::string &str)