...
 
Commits (7)
......@@ -74,6 +74,7 @@ protected:
//!< usually to facilitate SSL-encrypted communication (HTTPS)
//!< through an unencrypted HTTP proxy.
PATCH, //!< Is used to apply partial modifications to a resource.
CREATE, //!< internal method used by Xrdhttp - creates a file without payload
};
public:
......@@ -133,6 +134,7 @@ public:
else if (method == "OPTIONS") return Methods::OPTIONS;
else if (method == "CONNECT") return Methods::CONNECT;
else if (method == "PATCH") return Methods::PATCH;
else if (method == "CREATE") return Methods::CREATE;
else return -1;
}
};
......
......@@ -41,10 +41,11 @@ HttpRequest::HttpRequest (HeaderMap headers,
const std::string &query,
const std::string &body,
size_t *bodySize,
HeaderMap cookies) :
HeaderMap cookies,
bool xrdhttp) :
mRequestHeaders(headers), mRequestMethod(method), mRequestUrl(url),
mRequestQuery(query), mRequestBody(body), mRequestBodySize(bodySize),
mRequestCookies(cookies) {}
mRequestCookies(cookies),mXrdHttp(xrdhttp) {}
/*----------------------------------------------------------------------------*/
std::string
......
......@@ -53,6 +53,7 @@ private:
const std::string mRequestBody; //!< the client request body
size_t *mRequestBodySize; //!< the size of the client request body
HeaderMap mRequestCookies; //!< the client request cookie header map
bool mXrdHttp; //!< the request came with XrdHttp
public:
......@@ -66,6 +67,7 @@ public:
* @param body the request body data sent by the client
* @param bodysize the size of the request body
* @param cookies the map of cookie headers
* @param xrdhttp indicate an xrdhttp request
*/
HttpRequest (HeaderMap headers,
const std::string &method,
......@@ -73,7 +75,8 @@ public:
const std::string &query,
const std::string &uploadData,
size_t *uploadDataSize,
HeaderMap cookies);
HeaderMap cookies,
bool xrdhttp = false);
/**
* Destructor
......@@ -121,6 +124,12 @@ public:
*/
inline HeaderMap&
GetCookies () { return mRequestCookies; }
/**
* @return true if xrdhttp request
*/
inline bool&
IsXrdHttp () { return mXrdHttp; }
/**
* Change the request query string, useful in the case where a capability
......
......@@ -138,6 +138,40 @@ set_target_properties(jerasure-static PROPERTIES
target_link_libraries(jerasure-static PRIVATE gf-complete-static)
#-------------------------------------------------------------------------------
# EosFstHttp library
#-------------------------------------------------------------------------------
add_library(
EosFstHttp-Objects OBJECT
http/xrdhttp/EosFstHttpHandler.hh
http/xrdhttp/EosFstHttpHandler.cc
)
set_target_properties(
EosFstHttp-Objects
PROPERTIES
POSITION_INDEPENDENT_CODE TRUE)
add_library(EosFstHttp MODULE
$<TARGET_OBJECTS:EosFstHttp-Objects>
)
target_link_libraries(
EosFstHttp PUBLIC
XrdHttp-4
eosCommon
eosCommonServer
)
install(
TARGETS EosFstHttp
LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR})
#-------------------------------------------------------------------------------
# EosFstIo-Objects library
#-------------------------------------------------------------------------------
......
......@@ -89,6 +89,10 @@ extern "C"
const char* configFn,
XrdOucEnv* envP)
{
if (XrdOfsFS) {
return XrdOfsFS;
}
OfsEroute.SetPrefix("FstOfs_");
OfsEroute.logger(Logger);
// Disable XRootD log rotation
......@@ -115,7 +119,7 @@ EOSFSTNAMESPACE_BEGIN
// Constructor
//------------------------------------------------------------------------------
XrdFstOfs::XrdFstOfs() :
eos::common::LogId(), mHostName(NULL), mHttpd(0),
eos::common::LogId(), mHostName(NULL),
Simulate_IO_read_error(false), Simulate_IO_write_error(false),
Simulate_XS_read_error(false), Simulate_XS_write_error(false),
Simulate_FMD_open_error(false)
......@@ -144,6 +148,8 @@ XrdFstOfs::XrdFstOfs() :
gOFS.WOpenFid.set_deleted_key(0);
gOFS.WNoDeleteOnCloseFid.clear_deleted_key();
gOFS.WNoDeleteOnCloseFid.set_deleted_key(0);
setenv("EOSFSTOFS", std::to_string((unsigned long long)this).c_str(),1);
}
//------------------------------------------------------------------------------
......@@ -151,9 +157,6 @@ XrdFstOfs::XrdFstOfs() :
//------------------------------------------------------------------------------
XrdFstOfs::~XrdFstOfs()
{
if (mHttpd) {
delete mHttpd;
}
}
//------------------------------------------------------------------------------
......@@ -723,10 +726,9 @@ XrdFstOfs::Configure(XrdSysError& Eroute, XrdOucEnv* envP)
mHttpdPort = strtol(getenv("EOS_FST_HTTP_PORT"), 0, 10);
}
mHttpd = new HttpServer(mHttpdPort);
if (mHttpd) {
mHttpd->Start();
Httpd.reset(new eos::fst::HttpServer(mHttpdPort));
if (mHttpdPort) {
Httpd->Start();
}
eos_notice("FST_HOST=%s FST_PORT=%ld FST_HTTP_PORT=%d VERSION=%s RELEASE=%s KEYTABADLER=%s",
......
......@@ -380,8 +380,9 @@ public:
const char* mHostName; ///< FST hostname
QdbContactDetails mQdbContactDetails; ///< QDB contact details
int mHttpdPort; ///< listening port of the http server
std::unique_ptr<HttpServer> Httpd; //< Embedded http server if available
private:
HttpServer* mHttpd; ///< Embedded http server
bool Simulate_IO_read_error; ///< simulate an IO error on read
bool Simulate_IO_write_error; ///< simulate an IO error on write
bool Simulate_XS_read_error; ///< simulate a checksum error on read
......
......@@ -56,8 +56,8 @@ HttpHandler::Matches(const std::string& meth, HeaderMap& headers)
{
int method = ParseMethodString(meth);
// We only support GET, HEAD and PUT on the FST
if (method == GET || method == HEAD || method == PUT) {
// We only support GET, HEAD and PUT on the FST (CREATE is used by XrdHttp)
if (method == GET || method == HEAD || method == PUT || method == CREATE ) {
eos_static_info("Matched HTTP protocol for request");
return true;
} else {
......@@ -89,7 +89,8 @@ HttpHandler::HandleRequest(eos::common::HttpRequest* request)
query += request->GetHeaders()["x-upload-range"].c_str();
}
if (request->GetMethod() == "PUT") {
if ( (request->GetMethod() == "PUT") ||
(request->GetMethod() == "CREATE") ) {
// use the proper creation/open flags for PUT's
open_mode |= SFS_O_CREAT;
......@@ -182,6 +183,13 @@ HttpHandler::HandleRequest(eos::common::HttpRequest* request)
mHttpResponse = Get(request);
}
if (request->GetMethod() == "CREATE") {
// fake method for XrdHttp bridge
mHttpResponse = new eos::common::PlainHttpResponse();
mHttpResponse->SetResponseCode(0);
return;
}
if (request->GetMethod() == "PUT") {
if (((mUploadLeftSize > (1 * 1024 * 1024)) &&
((*request->GetBodySize()) < (1 * 1024 * 1024)))) {
......@@ -541,6 +549,7 @@ HttpHandler::Put(eos::common::HttpRequest* request)
*request->GetBodySize());
if (stored != *request->GetBodySize()) {
eos_static_err("stored %lu of %lu bytes", stored, *request->GetBodySize());
// HTTP write error
mErrCode = response->INTERNAL_SERVER_ERROR;
mErrText = "Write error occured";
......
......@@ -26,6 +26,7 @@
#include "fst/http/ProtocolHandlerFactory.hh"
#include "fst/XrdFstOfsFile.hh"
#include "common/http/ProtocolHandler.hh"
#include "common/SecEntity.hh"
#include "fst/XrdFstOfs.hh"
/*----------------------------------------------------------------------------*/
#include "XrdSys/XrdSysPthread.hh"
......@@ -180,6 +181,79 @@ HttpServer::Handler(void* cls,
}
}
/*----------------------------------------------------------------------------*/
ssize_t
HttpServer::FileReader(eos::common::ProtocolHandler* handler, uint64_t pos, char* buf, size_t max)
{
return HttpServer::FileReaderCallback(handler, pos, buf, max);
}
/*----------------------------------------------------------------------------*/
ssize_t
HttpServer::FileWriter(eos::common::ProtocolHandler* handler,
std::string& method,
std::string& uri,
std::map<std::string,std::string>& headers,
std::string& query,
std::map<std::string,std::string>& cookies,
std::string& body)
{
eos::fst::HttpHandler* httpHandle = dynamic_cast<eos::fst::HttpHandler*>
(handler);
size_t uploadSize = body.size();
std::unique_ptr<eos::common::HttpRequest> request ( new eos::common::HttpRequest(
headers, method, uri,
query.c_str(),
body, &uploadSize, cookies,
true));
eos_static_debug("\n\n%s", request->ToString().c_str());
// Handle the request and build a response based on the specific protocol
httpHandle->HandleRequest(request.get());
eos::common::HttpResponse* response = handler->GetResponse();
if (response->GetResponseCode() == response->CREATED)
return 0;
else
return -1;
}
/*----------------------------------------------------------------------------*/
ssize_t
HttpServer::FileClose(eos::common::ProtocolHandler* handler, int rc)
{
eos::fst::HttpHandler* httpHandle = dynamic_cast<eos::fst::HttpHandler*>
(handler);
if (httpHandle && httpHandle->mFile) {
if (rc) {
eos_static_err("msg=\"clean-up interrupted or IO error related PUT/GET request\" path=\"%s\"",
httpHandle->mFile->GetPath().c_str());
// we have to disable delete-on-close for chunked uploads since files are stateful
if (httpHandle->mFile->IsChunkedUpload()) {
httpHandle->mFile->close();
}
} else {
httpHandle->mFile->close();
}
// clean-up file objects
if (httpHandle->mFile) {
delete(httpHandle->mFile);
httpHandle->mFile = 0;
}
}
return 0;
}
/*----------------------------------------------------------------------------*/
ssize_t
HttpServer::FileReaderCallback(void* cls, uint64_t pos, char* buf, size_t max)
......@@ -194,7 +268,6 @@ HttpServer::FileReaderCallback(void* cls, uint64_t pos, char* buf, size_t max)
eos_static_err("error: dynamic cast to eos::fst::HttpHandler failed");
return -1;
}
eos_static_debug("pos=%llu max=%llu current-index=%d current-offset=%llu",
(unsigned long long) pos,
(unsigned long long) max,
......@@ -312,6 +385,49 @@ HttpServer::FileReaderCallback(void* cls, uint64_t pos, char* buf, size_t max)
return 0;
}
std::unique_ptr<eos::common::ProtocolHandler>
HttpServer::XrdHttpHandler(std::string& method,
std::string& uri,
std::map<std::string,std::string>& headers,
std::string& query,
std::map<std::string,std::string>& cookies,
std::string& body,
const XrdSecEntity& client)
{
if (client.moninfo && strlen(client.moninfo)) {
headers["ssl_client_s_dn"] = client.moninfo;
headers["x-real-ip"] = client.host;
}
ProtocolHandlerFactory factory = ProtocolHandlerFactory();
std::unique_ptr<eos::common::ProtocolHandler> handler ( factory.CreateProtocolHandler(method, headers, 0) );
if (!handler) {
eos_static_err("msg=\"no matching protocol for request method %s\"",
method);
return 0;
}
size_t bodySize = body.length();
// Retrieve the protocol handler stored in *ptr
std::unique_ptr<eos::common::HttpRequest> request ( new eos::common::HttpRequest(
headers, method, uri,
query.c_str() ? query : "",
body, &bodySize, cookies, true) );
if (EOS_LOGS_DEBUG) {
eos_static_debug("\n\n%s\n%s\n", request->ToString().c_str(),
request->GetBody().c_str());
}
handler->HandleRequest(request.get());
if (EOS_LOGS_DEBUG) {
eos_static_debug("method=%s uri='%s' %s (warning this is not the mapped identity)",method.c_str(), uri.c_str(), eos::common::SecEntity::ToString(&client,"xrdhttp").c_str());
}
return handler;
}
void
HttpServer::CompleteHandler(void* cls,
struct MHD_Connection* connection,
......
......@@ -34,6 +34,7 @@
#include "fst/Namespace.hh"
#include "common/Logging.hh"
#include "common/http/HttpServer.hh"
#include "common/http/ProtocolHandler.hh"
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
......@@ -71,6 +72,22 @@ public:
size_t* upload_data_size,
void** ptr);
/**
* HTTP object handler function on FST called by XrdHttp
*
* @return see implementation
*/
virtual std::unique_ptr<eos::common::ProtocolHandler>
XrdHttpHandler(std::string& method,
std::string& uri,
std::map<std::string,std::string>& headers,
std::string& query,
std::map<std::string,std::string>& cookies,
std::string& body,
const XrdSecEntity& client
);
/**
* HTTP complete handler function
*
......@@ -95,6 +112,21 @@ public:
static ssize_t
FileReaderCallback(void* cls, uint64_t pos, char* buf, size_t max);
virtual ssize_t
FileReader(eos::common::ProtocolHandler* handler, uint64_t pos, char* buf, size_t max);
virtual ssize_t
FileWriter(eos::common::ProtocolHandler* handler,
std::string& method,
std::string& uri,
std::map<std::string,std::string>& headers,
std::string& query,
std::map<std::string,std::string>& cookies,
std::string& body);
virtual ssize_t
FileClose(eos::common::ProtocolHandler* handler, int rc);
#endif
};
......
#include <stdio.h>
#include "XrdSfs/XrdSfsInterface.hh"
#include "common/Logging.hh"
#include "fst/XrdFstOfs.hh"
#include "fst/http/HttpServer.hh"
#include "common/http/ProtocolHandler.hh"
#include "common/StringConversion.hh"
#include "common/Timing.hh"
#include "EosFstHttpHandler.hh"
XrdVERSIONINFO(XrdSfsGetFileSystem, EosFstHttp);
bool
EosFstHttpHandler::MatchesPath(const char *verb, const char *path)
{
if (EOS_LOGS_DEBUG) {
eos_static_debug("verb=%s path=%s", verb, path);
}
if (std::string(verb) == "COPY") {
return false;
} else {
return true;
}
}
int
EosFstHttpHandler::ProcessReq(XrdHttpExtReq &req)
{
std::string body;
if (!OFS) {
eos_static_crit("OFS not accessible");
return -1;
}
std::map<std::string,std::string> cookies;
// normalize the input headers to lower-case
std::map<std::string,std::string> normalized_headers;
for (auto it = req.headers.begin(); it != req.headers.end(); ++it) {
normalized_headers[LC_STRING(it->first)] = it->second;
}
std::string query = normalized_headers.count("xrd-http-query")? normalized_headers["xrd-http-query"]: "";
std::string verb = req.verb;
if (req.verb == "PUT") {
verb = "CREATE"; // CREATE makes sure, the the handler just opens the file and all writes are done later
}
std::unique_ptr<eos::common::ProtocolHandler> handler = OFS->Httpd->XrdHttpHandler(verb,
req.resource,
normalized_headers,
query,
cookies,
body,
req.GetSecEntity());
eos::common::HttpResponse* response = handler->GetResponse();
if (response) {
std::string header;
response->AddHeader("Date", eos::common::Timing::utctime(time(NULL)));
off_t content_length = 0;
auto headers = response->GetHeaders();
for ( auto it = headers.begin(); it != headers.end(); ++it) {
if (it->first == "Content-Length") {
// this is added by SendSimpleResp, don't add it here
content_length = strtoull(it->second.c_str(), 0, 10);
continue;
}
header += it->first;
header += ": ";
header += it->second;
header += "\r\n";
}
if (headers.size()) {
header.erase(header.length()-2);
}
if (EOS_LOGS_DEBUG) {
eos_static_debug("response-header: %s", header.c_str());
}
if ( req.verb == "HEAD" ) {
return req.SendSimpleResp(response->GetResponseCode(), response->GetResponseCodeDescription().c_str(),
header.c_str(), response->GetBody().c_str(), response->GetBody().length());
}
if ( req.verb == "GET") {
if (response->GetResponseCode() != 200) {
return req.SendSimpleResp(response->GetResponseCode(), response->GetResponseCodeDescription().c_str(),
header.c_str(), response->GetBody().c_str(), response->GetBody().length());
} else {
int retc = 0;
retc = req.SendSimpleResp(0, response->GetResponseCodeDescription().c_str(),
header.c_str(), 0 , content_length);
if (retc)
return retc;
ssize_t nread = 0;
off_t pos = 0;
// allocate an IO buffer of 1M or if smaller the required content length
std::vector<char> buffer (content_length > (1*1024*1024)? (1*1024*1024): content_length);
do {
if (EOS_LOGS_DEBUG) {
eos_static_debug("pos=%llu size=%u", pos, buffer.capacity());
}
nread = OFS->Httpd->FileReader(handler.get(),pos, &buffer[0], buffer.capacity());
if (nread >= 0) {
pos += nread;
retc |= req.SendSimpleResp(1, 0, 0, &buffer[0], nread);
eos_static_debug("retc=%d", retc);
} else {
retc = -1;
}
} while ( (pos != content_length) && (nread>0) && !retc);
OFS->Httpd->FileClose(handler.get(), retc);
return retc;
}
}
if ( req.verb == "PUT") {
content_length = strtoull(normalized_headers.count("content-length")? normalized_headers["content-length"].c_str(): "-1",0,10);
if (EOS_LOGS_DEBUG) {
eos_static_debug("response-code=%d", response->GetResponseCode());
}
if (( response->GetResponseCode() != 0 ) &&
( response->GetResponseCode() != 200 )
) {
return req.SendSimpleResp(response->GetResponseCode(), response->GetResponseCodeDescription().c_str(),
header.c_str(), response->GetBody().c_str(), response->GetBody().length());
} else {
if ( (response->GetResponseCode() == 0) && normalized_headers.count("expect") &&
( normalized_headers["expect"] == "100-continue" ) ) {
// reply to 100-CONTINUE request
if (EOS_LOGS_DEBUG) {
eos_static_debug("sending 100-continue");
}
req.SendSimpleResp(100, "","","",0);
}
int retc = 0;
off_t content_left = content_length;
do {
size_t content_read = std::min(1*1024*1024l, content_left);
char* data = 0;
size_t rbytes = req.BuffgetData(content_read, &data, true);
// @TODO: improve me by avoiding to copy the buffer
body.reserve(content_read);
body.assign(data, rbytes);
if (EOS_LOGS_DEBUG) {
eos_static_info("content-read=%lu rbytes=%lu body=%u", content_read, rbytes, body.size());
}
if (rbytes != content_read) {
eos_static_crit("short read during put - receveid %lu instead of %lu bytes",
content_read, rbytes);
retc = -1;
} else {
retc |= OFS->Httpd->FileWriter(handler.get(),
req.verb,
req.resource,
normalized_headers,
query,
cookies,
body);
if (!retc) {
content_left -= content_read;
}
}
} while ( !retc && content_left );
if (EOS_LOGS_DEBUG) {
eos_static_debug("retc=%d", retc);
}
if (!retc) {
// trigger the close handler by calling with empty body
body.clear();
retc |= OFS->Httpd->FileWriter(handler.get(),
req.verb,
req.resource,
normalized_headers,
query,
cookies,
body);
}
eos::common::HttpResponse* response = handler->GetResponse();
if (response && response->GetResponseCode()) {
return req.SendSimpleResp(response->GetResponseCode(), response->GetResponseCodeDescription().c_str(),
header.c_str(), response->GetBody().c_str(), response->GetBody().length());
} else {
return req.SendSimpleResp(500, "fatal internal error", "", "", 0);
}
}
}
return 0;
} else {
std::string errmsg = "failed to create response object";
return req.SendSimpleResp(500, errmsg.c_str(), "", errmsg.c_str(), errmsg.length());
}
}
int
EosFstHttpHandler::Init(const char *cfgfile)
{
if (getenv("EOSFSTOFS")) {
OFS = (eos::fst::XrdFstOfs*) (strtoull(getenv("EOSFSTOFS"),0,10));
}
std::string cfg;
eos::common::StringConversion::LoadFileIntoString(cfgfile, cfg);
size_t fpos = cfg.find("xrd.protocol XrdHttp:");
if ( fpos != std::string::npos) {
size_t epos = cfg.find(" ", fpos+21);
if (epos != std::string::npos) {
std::string port = cfg.substr(fpos+21, epos-fpos-21);
setenv("EOSFSTXRDHTTP",port.c_str(),1);
eos_static_notice("publishing HTTP port: %s", port.c_str());
}
}
return 0;
}
#pragma once
#include <map>
#include <string>
#include "XrdHttp/XrdHttpExtHandler.hh"
#include "XrdVersion.hh"
XrdVERSIONINFO(XrdHttpGetExtHandler, EOSFSTHTTP );
class XrdLink;
class XrdSecEntity;
class XrdHttpReq;
class XrdHttpProtocol;
class EosFstHttpHandler : public XrdHttpExtHandler {
public:
bool MatchesPath(const char *verb, const char *path);
int ProcessReq(XrdHttpExtReq &);
int Init(const char *cfgfile);
//------------------------------------------------------------------------------
//! Constructor
//------------------------------------------------------------------------------
EosFstHttpHandler() {}
//------------------------------------------------------------------------------
//! Destructor
//------------------------------------------------------------------------------
virtual ~EosFstHttpHandler() {}
private:
eos::fst::XrdFstOfs* OFS;
};
/******************************************************************************/
/* X r d H t t p G e t E x t H a n d l e r */
/******************************************************************************/
//------------------------------------------------------------------------------
//! 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.
//!
//------------------------------------------------------------------------------
class XrdSysError;
class XrdOucEnv;
#define XrdHttpExtHandlerArgs XrdSysError *eDest, \
const char *confg, \
const char *parms, \
XrdOucEnv *myEnv
extern "C" XrdHttpExtHandler *XrdHttpGetExtHandler(XrdHttpExtHandlerArgs) {
XrdHttpExtHandler* handler = new EosFstHttpHandler();
handler->Init(confg);
return handler;
}
//------------------------------------------------------------------------------
//! Declare compilation version.
//!
//! Additionally, you *should* declare the xrootd version you used to compile
//! your plug-in. While not currently required, it is highly recommended to
//! avoid execution issues should the class definition change. Declare it as:
//------------------------------------------------------------------------------
XrdHttp
-------
HTTP(S) using the XRootD thread-pool and XrdHttp can be enabled in ```/etc/xrd.cf.fst``` like:
```
if exec xrootd
xrd.protocol XrdHttp:9000 /usr/lib64/libXrdHttp-4.so
http.exthandler EosFstHttp /usr/lib64/libEosFstHttp.so none
http.cert /etc/grid-security/daemon/host.cert
http.key /etc/grid-security/daemon/privkey.pem
http.cafile /etc/grid-security/daemon/ca.cert
fi
```
To disable HTTPS you can remove the cert/key/cafile directives.
The targetport in redirection is currently taken from the sysconfig file and uses ```EOS_FST_HTTP_PORT+1000```.
The protocol used for data transfers is configured on the MGM. By defaul HTTPS access redirects to HTTP on the data server if not modified in the MGM configuration file.
......@@ -359,7 +359,13 @@ Storage::Publish()
mFsVect[i]->getIOPS());
success &= mFsVect[i]->SetDouble("stat.disk.bw",
mFsVect[i]->getSeqBandwidth()); // in MB
success &= mFsVect[i]->SetLongLong("stat.http.port", gOFS.mHttpdPort);
if (getenv("EOSFSTXRDHTTP")) {
success &= mFsVect[i]->SetLongLong("stat.http.port", strtoull(getenv("EOSFSTXRDHTTP"),0,10));
} else {
success &= mFsVect[i]->SetLongLong("stat.http.port", gOFS.mHttpdPort);
}
{
// we have to set something which is not empty to update the value
if (!r_open_hotfiles.length()) {
......
......@@ -250,7 +250,7 @@ add_library(EosMgmHttp MODULE
target_link_libraries(
EosMgmHttp PUBLIC
XrdHttpUtils
XrdHttp-4
eosCommon
eosCommonServer
)
......
......@@ -120,6 +120,10 @@ XrdSfsGetFileSystem(XrdSfsFileSystem* native_fs,
XrdSysLogger* lp,
const char* configfn)
{
if (gOFS) {
// initialize filesystems only once
return gOFS;
}
gMgmOfsEroute.SetPrefix("MgmOfs_");
gMgmOfsEroute.logger(lp);
static XrdMgmOfs myFS(&gMgmOfsEroute);
......
......@@ -13,6 +13,10 @@ XrdVERSIONINFO(XrdSfsGetFileSystem, EosMgmHttp);
bool
EosMgmHttpHandler::MatchesPath(const char *verb, const char *path)
{
if (std::string(verb) == "POST") {
return false;
}
if (EOS_LOGS_DEBUG) {
eos_static_debug("verb=%s path=%s", verb, path);
}
......@@ -60,14 +64,28 @@ EosMgmHttpHandler::ProcessReq(XrdHttpExtReq &req)
response->AddHeader("Date", eos::common::Timing::utctime(time(NULL)));
auto headers = response->GetHeaders();
for ( auto it = headers.begin(); it != headers.end(); ++it) {
if (it->first == "Content-Length") {
std::string key = it->first;
std::string val = it->second;
if (key == "Content-Length") {
// this is added by SendSimpleResp, don't add it here
continue;
}
header += it->first;
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") ) {
// write http: as https:
val.insert(4,"s");
}
}
}
}
header += key;
header += ": ";
header += it->second;
header += val;
header += "\r\n";
}
......@@ -91,6 +109,15 @@ EosMgmHttpHandler::Init(const char *cfgfile)
{
if (getenv("EOSMGMOFS")) {
OFS = (XrdMgmOfs*) (strtoull(getenv("EOSMGMOFS"),0,10));
std::string cfg;
eos::common::StringConversion::LoadFileIntoString(cfgfile, cfg);
if (cfg.find("eos::mgm::http::redirect-to-https=1") != std::string::npos) {
mRedirectToHttps = true;
}
eos_static_notice("configuration: redirect-to-https:%d", mRedirectToHttps);
}
return 0;
}
......
......@@ -28,7 +28,7 @@ public:
//! Constructor
//------------------------------------------------------------------------------
EosMgmHttpHandler() {}
EosMgmHttpHandler() : mRedirectToHttps(false) {}
//------------------------------------------------------------------------------
//! Destructor
......@@ -38,6 +38,7 @@ public:
private:
XrdMgmOfs* OFS;
bool mRedirectToHttps;
};
/******************************************************************************/
......
XrdHttp
-------
HTTP(S) using the XRootD thread-pool and XrdHttp can be enabled in ```/etc/xrd.cf.mgm``` like:
```
if exec xrootd
xrd.protocol XrdHttp:9000 /usr/lib64/libXrdHttp-4.so
http.exthandler EosMgmHttp /usr/lib64/libEosMgmHttp.so eos::mgm::http::redirect-to-https=1
http.cert /etc/grid-security/daemon/host.cert
http.key /etc/grid-security/daemon/privkey.pem
http.cafile /etc/grid-security/daemon/ca.cert
fi
```
To disabel HTTPS you can remove the cert/key/cafile directives. If you want to redirect the data transfer from HTTPS to HTTP you can change the configuration key to ```eos::mgm::http::redirect-to-https=0``` or just put ```none``` at this place.
The targetport in redirection is currently taken from the sysconfig file and uses ```EOS_FST_HTTP_PORT+1000```.
###########################################################
###########################################################
set MGM=$EOS_MGM_ALIAS
###########################################################
......@@ -30,3 +30,14 @@ fstofs.quotainterval 10
fstofs.metalog /var/eos/md/
#fstofs.trace client
###########################################################
#-------------------------------------------------------------------------------
# Configuration for XrdHttp http(s) service on port 11000
#-------------------------------------------------------------------------------
#if exec xrootd
# xrd.protocol XrdHttp:11000 /usr/lib64/libXrdHttp-4.so
# http.exthandler EosFstHttp /usr/lib64/libEosFstHttp.so none
# http.cert /etc/grid-security/daemon/host.cert
# http.key /etc/grid-security/daemon/privkey.pem
# http.cafile /etc/grid-security/daemon/ca.cert
#fi
Subproject commit 8abb193f75942373c47e898b96d072ba03b17da7
Subproject commit b03c43d54abdc9f1da7db72593f99e1f9cadc444