//------------------------------------------------------------------------------ //! file EosMgmHttpHandler.cc //------------------------------------------------------------------------------ /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2019 CERN/Switzerland * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* ************************************************************************/ #include "EosMgmHttpHandler.hh" #include "common/Logging.hh" #include "mgm/XrdMgmOfs.hh" #include "mgm//http/HttpServer.hh" #include "common/http/ProtocolHandler.hh" #include "common/StringConversion.hh" #include "common/StringTokenizer.hh" #include "common/StringUtils.hh" #include "common/Timing.hh" #include "common/Path.hh" #include "XrdSec/XrdSecEntityAttr.hh" #include "XrdSfs/XrdSfsInterface.hh" #include "XrdSys/XrdSysPlugin.hh" #include "XrdAcc/XrdAccAuthorize.hh" #include "XrdOuc/XrdOucPinPath.hh" #include #include "mgm/http/rest-api/manager/RestApiManager.hh" XrdVERSIONINFO(XrdHttpGetExtHandler, EosMgmHttp); static XrdVERSIONINFODEF(compiledVer, EosMgmHttp, XrdVNUMBER, XrdVERSION); //------------------------------------------------------------------------------ //! Obtain an instance of the XrdHttpExtHandler object. //! //! This extern "C" function is called when a shared library plug-in containing //! implementation of this class is loaded. It must exist in the shared library //! and must be thread-safe. //! //! @param eDest -> The error object that must be used to print any errors or //! other messages (see XrdSysError.hh). //! @param confg -> Name of the configuration file that was used. This pointer //! may be null though that would be impossible. //! @param parms -> Argument string specified on the namelib directive. It may //! be null or point to a null string if no parms exist. //! @param myEnv -> Environment variables for configuring the external handler; //! it my be null. //! //! @return Success: A pointer to an instance of the XrdHttpSecXtractor object. //! Failure: A null pointer which causes initialization to fail. //! //------------------------------------------------------------------------------ #define XrdHttpExtHandlerArgs XrdSysError *eDest, \ const char *confg, \ const char *parms, \ XrdOucEnv *myEnv extern "C" XrdHttpExtHandler* XrdHttpGetExtHandler(XrdHttpExtHandlerArgs) { auto handler = new EosMgmHttpHandler(); if (handler->Init(confg)) { delete handler; return nullptr; } if (handler->Config(eDest, confg, parms, myEnv)) { eDest->Emsg("EosMgmHttpHandler", EINVAL, "Failed config of EosMgmHttpHandler"); delete handler; return nullptr; } return (XrdHttpExtHandler*)handler; } //---------------------------------------------------------------------------- //! Destructor //---------------------------------------------------------------------------- EosMgmHttpHandler::~EosMgmHttpHandler() { eos_info("msg=\"call %s destructor\"", __FUNCTION__); } //------------------------------------------------------------------------------ // Configure the external request handler //------------------------------------------------------------------------------ int EosMgmHttpHandler::Config(XrdSysError* eDest, const char* confg, const char* parms, XrdOucEnv* myEnv) { using namespace eos::common; const std::string ofs_lib_tag = "xrootd.fslib"; const std::string authz_lib_tag = "mgmofs.macaroonslib"; std::list authz_libs; std::string ofs_lib_path, http_ext_lib_path; std::string cfg; StringConversion::LoadFileIntoString(confg, cfg); auto lines = StringTokenizer::split>(cfg, '\n'); for (auto& line : lines) { eos::common::trim(line); if (line.find("eos::mgm::http::redirect-to-https=1") != std::string::npos) { mRedirectToHttps = true; } else if (line.find(ofs_lib_tag) == 0) { ofs_lib_path = GetOfsLibPath(line); // XRootD guarantees that the XRootD protocol and its associated // plugins are loaded before HTTP therefore we can get a pointer // to the MGM OFS plugin mMgmOfsHandler = GetOfsPlugin(eDest, ofs_lib_path, confg); if (!mMgmOfsHandler) { eDest->Emsg("Config", "failed to get MGM OFS plugin pointer"); return 1; } } else if (line.find(authz_lib_tag) == 0) { authz_libs = GetAuthzLibPaths(line); http_ext_lib_path = GetHttpExtLibPath(line); if (authz_libs.empty() || http_ext_lib_path.empty()) { eos_err("msg=\"wrong mgmofs.macaroonslib configuration\" data=\"%s\"", line.c_str()); return 1; } } } if (authz_libs.empty() || http_ext_lib_path.empty()) { eos_notice("%s", "msg=\"mgmofs.macaroonslib configuration missing so " "there is no token authorization support\""); return 0; } if (!mMgmOfsHandler || !mMgmOfsHandler->mMgmAuthz) { eos_err("%s", "msg=\"missing MGM OFS handler or MGM AUTHZ handler\""); return 1; } eos_notice("configuration: redirect-to-https:%d", mRedirectToHttps); // Load the XrdHttpExHandler plugin from the XrdMacaroons library which // is always on the first position if (!(mTokenHttpHandler = GetHttpExtPlugin(eDest, *authz_libs.begin(), confg, myEnv))) { return 1; } // The chaining of the authz libs always has the XrdAccAuthorize plugin // from the MGM in the last postion as a fallback. Therefore, we can // have the following combinations: // libXrdMacaroons.so -> libEosMgmOfs.so // libXrdMacaroons.so -> libXrdAccSciTokens.so -> libEosMgmOfs.so XrdAccAuthorize* authz {nullptr}; XrdAccAuthorize* chain_authz = (XrdAccAuthorize*)mMgmOfsHandler->mMgmAuthz; for (auto it = authz_libs.rbegin(); it != authz_libs.rend(); ++it) { eos_info("msg=\"chaining XrdAccAuthorize object\" lib=\"%s\"", it->c_str()); try { if (!(authz = GetAuthzPlugin(eDest, *it, confg, myEnv, chain_authz))) { eos_err("msg=\"failed to chain XrdAccAuthorize plugin\" lib=\"%s\"", it->c_str()); return 1; } } catch (const std::exception& e) { eos_err("msg=\"caught exception\" msg=\"%s\"", e.what()); return 1; } chain_authz = authz; } eos_info("%s", "msg=\"successfully chained the XrdAccAuthorizeObject " "plugins and updated the MGM token authorization handler\""); mTokenAuthzHandler = authz; mMgmOfsHandler->SetTokenAuthzHandler(mTokenAuthzHandler); return 0; } //------------------------------------------------------------------------------ // Decide if current handler should be invoked //------------------------------------------------------------------------------ bool EosMgmHttpHandler::MatchesPath(const char* verb, const char* path) { eos_static_info("verb=%s path=%s", verb, path); // Leave the XrdHttpTPC plugin deal with COPY/OPTIONS verbs if ((strcmp(verb, "COPY") == 0) || (strcmp(verb, "OPTIONS") == 0)) { return false; } return true; } //------------------------------------------------------------------------------ // Process the HTTP request and send the response using by calling the // XrdHttpProtocol directly //------------------------------------------------------------------------------ int EosMgmHttpHandler::ProcessReq(XrdHttpExtReq& req) { std::string body; // @todo(esindril): handle redirection to new MGM master if the // current one is a slave // Stop accepting requests if the MGM started the shutdown procedure if (mMgmOfsHandler->Shutdown) { std::string errmsg = "MGM daemon is shutting down"; return req.SendSimpleResp(500, errmsg.c_str(), nullptr, errmsg.c_str(), errmsg.length()); } // Normalize the input headers to lower-case std::map normalized_headers; for (const auto& hdr : req.headers) { eos_static_info("msg=\"normalize hdr\" key=\"%s\" value=\"%s\"", hdr.first.c_str(), hdr.second.c_str()); normalized_headers[LC_STRING(hdr.first)] = hdr.second; } if (IsMacaroonRequest(req)) { if (mTokenHttpHandler) { // Delegate request to the XrdMacaroons library eos_info("%s", "msg=\"delegate request to XrdMacaroons library\""); return ProcessMacaroonPOST(req); } else { std::string errmsg = "POST request not supported"; return req.SendSimpleResp(404, errmsg.c_str(), nullptr, errmsg.c_str(), errmsg.length()); } } if (mMgmOfsHandler->mRestGrpcSrv && IsRestApiRequest(req)) { return ProcessRestApiPost(req, normalized_headers); } bool is_rest_req = mMgmOfsHandler->mRestApiManager->isRestRequest( req.resource); if (is_rest_req) { std::optional retCode = readBody(req, body); if (retCode) { return retCode.value(); } } if (req.verb == "PROPFIND" && !is_rest_req) { // read the body body.resize(req.length); char* data = 0; int rbytes = req.BuffgetData(req.length, &data, true); body.assign(data, (size_t) rbytes); } std::string err_msg; std::map cookies; std::unique_ptr handler = mMgmOfsHandler->mHttpd->XrdHttpHandler (req.verb, req.resource, normalized_headers, cookies, body, req.GetSecEntity(), mTokenAuthzHandler, err_msg); if (handler == nullptr) { return req.SendSimpleResp(500, err_msg.c_str(), "", err_msg.c_str(), err_msg.length()); } eos::common::HttpResponse* response = handler->GetResponse(); if (response == nullptr) { std::string errmsg = "failed to create response object"; return req.SendSimpleResp(500, errmsg.c_str(), nullptr, errmsg.c_str(), errmsg.length()); } std::ostringstream oss_header; response->AddHeader("Date", eos::common::Timing::utctime(time(NULL))); const auto& headers = response->GetHeaders(); for (const auto& hdr : headers) { std::string key = hdr.first; std::string val = hdr.second; // This is added by SendSimpleResp, don't add it here if (key == "Content-Length") { continue; } if (mRedirectToHttps) { if (key == "Location") { if (normalized_headers["xrd-http-prot"] == "https") { if (!normalized_headers.count("xrd-http-redirect-http") || (normalized_headers["xrd-http-redirect-http"] == "0")) { // Re-write http: as https: val.insert(4, "s"); } } } } if (!oss_header.str().empty()) { oss_header << "\r\n"; } oss_header << key << ": " << val; } eos_debug("response-header=\"%s\"", oss_header.str().c_str()); if (req.verb == "HEAD") { long long content_length = 0; auto it = headers.find("Content-Length"); if (it != headers.end()) { try { content_length = std::stoll(it->second); } catch (...) {} } return req.SendSimpleResp(response->GetResponseCode(), response->GetResponseCodeDescription().c_str(), oss_header.str().c_str(), nullptr, content_length); } else { return req.SendSimpleResp(response->GetResponseCode(), response->GetResponseCodeDescription().c_str(), oss_header.str().c_str(), response->GetBody().c_str(), response->GetBody().length()); } } //------------------------------------------------------------------------------ // Process macaroon POST request //------------------------------------------------------------------------------ int EosMgmHttpHandler::ProcessMacaroonPOST(XrdHttpExtReq& req) { auto& sec_entity = const_cast(req.GetSecEntity()); // If the XrdSecEntity comes with VOMS extensions then we need to call the // eos vid mapping funcationality to actually determine the local user // mapping which could be different then the one embedded in the GSI auth. // This happens for example when we have VOMS mapping enabled in eos vid if (sec_entity.vorg && (sec_entity.vorg[0] != '\0')) { std::unique_ptr vid_tmp {new eos::common::VirtualIdentity()}; std::string stident = "https.0:0@" + std::string(sec_entity.host); eos::common::Mapping::IdMap(&sec_entity, "", stident.c_str(), *vid_tmp); if (!vid_tmp->uid_string.empty()) { free(sec_entity.name); sec_entity.name = strndup(vid_tmp->uid_string.c_str(), vid_tmp->uid_string.length()); } } return mTokenHttpHandler->ProcessReq(req); } //------------------------------------------------------------------------------ // Process rest api gw POST request //------------------------------------------------------------------------------ int EosMgmHttpHandler::ProcessRestApiPost(XrdHttpExtReq& req, const HdrsMapT& norm_hdrs) { std::string errmsg; // Extract request body std::string body; std::optional retCode = readBody(req, body); if (retCode) { return retCode.value(); } // Extract command name from the resource path // To do so search for the last occurrence of '/' std::string eosCommand; size_t lastSlashPos = req.resource.rfind('/'); if (lastSlashPos != std::string::npos && lastSlashPos + 1 < req.resource.length()) { // Extract the command string eosCommand = req.resource.substr(lastSlashPos + 1); } else { errmsg = "invalid input string"; eos_static_err("msg=\"%s\"", errmsg.c_str()); return req.SendSimpleResp(500, errmsg.c_str(), "", errmsg.c_str(), errmsg.length()); } // Initialize curl object CURL* curl = curl_easy_init(); if (!curl) { errmsg = "failed to initialize curl object"; eos_static_err("msg=\"%s\"", errmsg.c_str()); return req.SendSimpleResp(500, errmsg.c_str(), "", errmsg.c_str(), errmsg.length()); } // Set the URL for the POST request const std::string url = std::string(mRestApiGwUrl) + std::string( mRestApiGwPath) + eosCommand; curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // Set the HTTP method to POST curl_easy_setopt(curl, CURLOPT_POST, 1L); // Forward relevant headers for auth if (!RestApiGwFrwAuthHeaders(curl, req.GetSecEntity(), norm_hdrs)) { errmsg = "failure while forwarding auth headers"; eos_static_err("msg=\"%s\"", errmsg.c_str()); return req.SendSimpleResp(500, errmsg.c_str(), "", errmsg.c_str(), errmsg.length()); } // Set the request data curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str()); // Response data will be stored in this string std::string responseData; // Set the callback function to handle response data curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, EosMgmHttpHandler::WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseData); // Perform the HTTP request CURLcode curlRes = curl_easy_perform(curl); int res = 0; if (curlRes != CURLE_OK) { std::string errmsg = std::string("curl_easy_perform() failed: ") + curl_easy_strerror(curlRes); res = req.SendSimpleResp(500, errmsg.c_str(), "", errmsg.c_str(), errmsg.length()); } else { // HTTP request successful, send the response res = req.SendSimpleResp(200, responseData.c_str(), "", responseData.c_str(), responseData.length()); } // Clean up and free resources curl_easy_cleanup(curl); return res; } //---------------------------------------------------------------------------- // Forward the authentication relevant info as custom headers to the // GRPC-gateway that will then send them further down to the GRPC server //---------------------------------------------------------------------------- bool EosMgmHttpHandler::RestApiGwFrwAuthHeaders(CURL* curl, const XrdSecEntity& client, const HdrsMapT& norm_hdrs) { static const std::string hdr_prefix = "Grpc-Metadata-"; static const std::string authz_hdr = "authorization"; struct curl_slist* list = NULL; list = curl_slist_append(list, SSTR(hdr_prefix << "client-name: " << client.name).c_str()); list = curl_slist_append(list, SSTR(hdr_prefix << "client-tident: " << "https.0:0@" << client.host).c_str()); auto it_authz = norm_hdrs.find(authz_hdr); if (it_authz != norm_hdrs.end()) { list = curl_slist_append(list, SSTR(hdr_prefix << "client-authorization: " << it_authz->second).c_str()); } curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); return true; } //---------------------------------------------------------------------------- // Function used to handle responses from grpc server //---------------------------------------------------------------------------- size_t EosMgmHttpHandler::WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) { size_t total_size = size * nmemb; output->append(static_cast(contents), total_size); return total_size; } //------------------------------------------------------------------------------ // Get OFS library path from the given configuration //------------------------------------------------------------------------------ std::string EosMgmHttpHandler::GetOfsLibPath(const std::string& cfg_line) { using namespace eos::common; std::string lib_path; auto tokens = StringTokenizer::split>(cfg_line, ' '); if (tokens.size() < 2) { eos_err("msg=\"failed parsing xrootd.ofslib directive\" line=\"%s\"", cfg_line.c_str()); return lib_path; } eos::common::trim(tokens[1]); lib_path = tokens[1]; // Account for different specifications of the OFS plugin if (lib_path == "-2") { if (tokens.size() < 3) { eos_err("msg=\"failed parsing xrootd.ofslib directive\" line=\"%s\"", cfg_line.c_str()); lib_path.clear(); return lib_path; } eos::common::trim(tokens[2]); lib_path = tokens[2]; } return lib_path; } //------------------------------------------------------------------------------ // Get list of external authorization libraries present in the configuration. // If multiple are present then the order is kept to properly apply chaining // to these libraries. //------------------------------------------------------------------------------ std::list EosMgmHttpHandler::GetAuthzLibPaths(const std::string& cfg_line) { using namespace eos::common; std::list authz_libs; auto tokens = StringTokenizer::split>(cfg_line, ' '); if (tokens.size() < 2) { eos_err("msg=\"missing mgmofs.macaroonslib configuration\" " "tokens_sz=%i", tokens.size()); return authz_libs; } // The first one MUST BE the XrdMacroons lib eos::common::trim(tokens[1]); authz_libs.push_back(tokens[1]); // Enable also the SciTokens library if present in the configuration if (tokens.size() > 2) { eos::common::trim(tokens[2]); authz_libs.push_back(tokens[2]); } return authz_libs; } //---------------------------------------------------------------------------- // Get XrdHttpExHandler library path from the given configuration //---------------------------------------------------------------------------- std::string EosMgmHttpHandler::GetHttpExtLibPath(const std::string& cfg_line) { using namespace eos::common; auto tokens = StringTokenizer::split>(cfg_line, ' '); if (tokens.size() < 2) { eos_err("msg=\"missing mgmofs.macaroonslib configuration\" " "tokens_sz=%i", tokens.size()); return std::string(); } // The first one MUST BE the XrdMacroons lib eos::common::trim(tokens[1]); return tokens[1]; } //------------------------------------------------------------------------------ // Get a pointer to the MGM OFS plug-in //------------------------------------------------------------------------------ XrdMgmOfs* EosMgmHttpHandler::GetOfsPlugin(XrdSysError* eDest, const std::string& lib_path, const char* confg) { char resolve_path[2048]; bool no_alt_path {false}; XrdMgmOfs* mgm_ofs_handler {nullptr}; if (!XrdOucPinPath(lib_path.c_str(), no_alt_path, resolve_path, sizeof(resolve_path))) { eDest->Emsg("Config", "Failed to locate the MGM OFS library path for ", lib_path.c_str()); return mgm_ofs_handler; } // Try to load the XrdSfsGetFileSystem from the library (libXrdEosMgm.so) XrdSfsFileSystem *(*ep)(XrdSfsFileSystem*, XrdSysLogger*, const char*); std::string ofs_symbol {"XrdSfsGetFileSystem"}; XrdSysPlugin ofs_plugin(eDest, resolve_path, "mgmofs", &compiledVer, 1); void* ofs_addr = ofs_plugin.getPlugin(ofs_symbol.c_str(), 0, 0); ofs_plugin.Persist(); ep = (XrdSfsFileSystem * (*)(XrdSfsFileSystem*, XrdSysLogger*, const char*)) (ofs_addr); XrdSfsFileSystem* sfs_fs {nullptr}; if (!(ep && (sfs_fs = ep(nullptr, eDest->logger(), confg)))) { eDest->Emsg("Config", "Failed loading XrdSfsFileSystem from ", lib_path.c_str()); return mgm_ofs_handler; } mgm_ofs_handler = static_cast(sfs_fs); eos_info("msg=\"successfully loaed XrdSfsFileSystem\" mgm_plugin_addr=%p", mgm_ofs_handler); return mgm_ofs_handler; } //------------------------------------------------------------------------------ // Get a pointer to the XrdHttpExtHandler plugin //------------------------------------------------------------------------------ XrdHttpExtHandler* EosMgmHttpHandler::GetHttpExtPlugin(XrdSysError* eDest, const std::string& lib_path, const char* confg, XrdOucEnv* myEnv) { bool no_alt_path = false; char resolve_path[2048]; XrdHttpExtHandler* http_ptr {nullptr}; if (!XrdOucPinPath(lib_path.c_str(), no_alt_path, resolve_path, sizeof(resolve_path))) { eos_err("msg=\"failed to locate library path\" lib=\"%s\"", lib_path.c_str()); return http_ptr; } eos_info("msg=\"loading HttpExtHandler(XrdMacaroons) plugin\" path=\"%s\"", resolve_path); XrdHttpExtHandler *(*ep)(XrdHttpExtHandlerArgs); std::string http_symbol {"XrdHttpGetExtHandler"}; XrdSysPlugin http_plugin(eDest, resolve_path, "httpexthandler", &compiledVer, 1); void* http_addr = http_plugin.getPlugin(http_symbol.c_str(), 0, 0); http_plugin.Persist(); ep = (XrdHttpExtHandler * (*)(XrdHttpExtHandlerArgs))(http_addr); if (!http_addr) { eos_err("msg=\"no XrdHttpGetExtHandler entry point in library\" " "lib=\"%s\"", resolve_path); return http_ptr; } // Add a pointer to the MGM authz handler so that it can be used by the // macaroons library to get access permissions for token requests myEnv->PutPtr("XrdAccAuthorize*", (void*)mMgmOfsHandler->mMgmAuthz); if (ep && (http_ptr = ep(eDest, confg, (const char*) nullptr, myEnv))) { eos_info("msg=\"successfully loaded XrdHttpGetExtHandler\" lib=\"%s\"", resolve_path); } else { eos_err("msg=\"failed loading XrdHttpGetExtHandler\" lib=\"%s\"", resolve_path); } return http_ptr; } //------------------------------------------------------------------------------ // Get a pointer to the XrdAccAuthorize plugin present in the given library //------------------------------------------------------------------------------ XrdAccAuthorize* EosMgmHttpHandler::GetAuthzPlugin(XrdSysError* eDest, const std::string& lib_path, const char* confg, XrdOucEnv* myEnv, XrdAccAuthorize* to_chain) { bool no_alt_path = false; char resolve_path[2048]; XrdAccAuthorize* authz_ptr {nullptr}; if (!XrdOucPinPath(lib_path.c_str(), no_alt_path, resolve_path, sizeof(resolve_path))) { eos_err("msg=\"failed to locate library path\" lib=\"%s\"", lib_path.c_str()); return authz_ptr; } eos_info("msg=\"loading XrdAccAuthorize plugin\" lib=\"%s\"", resolve_path); XrdAccAuthorize *(*authz_add_ep)(XrdSysLogger*, const char*, const char*, XrdOucEnv*, XrdAccAuthorize*); std::string authz_add_symbol {"XrdAccAuthorizeObjAdd"}; XrdSysPlugin authz_add_plugin(eDest, resolve_path, "authz", &compiledVer, 1); void* authz_addr = authz_add_plugin.getPlugin(authz_add_symbol.c_str(), 0, 0); authz_add_plugin.Persist(); authz_add_ep = (XrdAccAuthorize * (*)(XrdSysLogger*, const char*, const char*, XrdOucEnv*, XrdAccAuthorize*))(authz_addr); if (authz_add_ep && (authz_ptr = authz_add_ep(eDest->logger(), confg, nullptr, myEnv, to_chain))) { eos_info("msg=\"successfully loaded XrdAccAuthorizeObject\" lib=\"%s\" ptr=%p", resolve_path, authz_ptr); } else { eos_err("msg=\"failed loading XrdAccAuthorizeObject\" lib=\"%s\"", resolve_path); } return authz_ptr; } //------------------------------------------------------------------------------ // Reads the body of the XrdHttpExtReq object and put it in the body string //------------------------------------------------------------------------------ std::optional EosMgmHttpHandler::readBody(XrdHttpExtReq& req, std::string& body) { std::optional returnCode; body.reserve(req.length); const unsigned long long eoshttp_sz = 1024 * 1024; const unsigned long long xrdhttp_sz = 256 * 1024; unsigned long long contentLeft = req.length; std::string bodyTemp; do { unsigned long long contentToRead = std::min(eoshttp_sz, contentLeft); bodyTemp.clear(); bodyTemp.reserve(contentToRead); char* data = nullptr; unsigned long long dataRead = 0; do { size_t chunk_len = std::min(xrdhttp_sz, contentToRead - dataRead); int bytesRead = req.BuffgetData(chunk_len, &data, true); eos_static_debug("contentToRead=%lli rb=%i body=%u contentLeft=%lli", contentToRead, bytesRead, body.size(), contentLeft); if (bytesRead > 0) { bodyTemp.append(data, bytesRead); dataRead += bytesRead; } else if (bytesRead == -1) { std::ostringstream oss; oss << "msg=\"In EosMgmHttpHandler::ProcessReq(), unable to read the " << "body of the request coming from the user. Internal XRootD Http" << " request buffer error\""; eos_static_err(oss.str().c_str()); std::string errorMsg = "Http server error: unable to read the request received"; return req.SendSimpleResp(500, errorMsg.c_str(), nullptr, errorMsg.c_str(), errorMsg.length()); } else { break; } } while (dataRead < contentToRead); contentLeft -= dataRead; body += bodyTemp; } while (contentLeft); return returnCode; } //------------------------------------------------------------------------------ // Returns true if the request is a macaroon token request false otherwise //------------------------------------------------------------------------------ bool EosMgmHttpHandler::IsMacaroonRequest(const XrdHttpExtReq& req) const { if (req.verb == "POST") { const auto& contentTypeItor = req.headers.find("Content-Type"); if (contentTypeItor != req.headers.end()) { if (contentTypeItor->second == "application/macaroon-request") { return true; } } } return false; } //------------------------------------------------------------------------------ // Returns true if the request is a rest api gateway token request // false otherwise // @todo(esindril) this should be moved in the GrpcRestGwServer //------------------------------------------------------------------------------ bool EosMgmHttpHandler::IsRestApiRequest(const XrdHttpExtReq& req) const { if (req.verb == "POST") { const auto& resourcePath = req.resource.find(mRestApiGwPath); if (resourcePath != std::string::npos) { return true; } } return false; }