XRootD
Loading...
Searching...
No Matches
XrdHttpProtocol.cc File Reference
#include "XrdVersion.hh"
#include "Xrd/XrdBuffer.hh"
#include "Xrd/XrdLink.hh"
#include "XProtocol/XProtocol.hh"
#include "XrdOuc/XrdOucStream.hh"
#include "XrdOuc/XrdOucEnv.hh"
#include "XrdOuc/XrdOucGMap.hh"
#include "XrdSys/XrdSysE2T.hh"
#include "XrdSys/XrdSysTimer.hh"
#include "XrdOuc/XrdOucPinLoader.hh"
#include "XrdHttpTrace.hh"
#include "XrdHttpProtocol.hh"
#include <sys/stat.h>
#include "XrdHttpUtils.hh"
#include "XrdHttpSecXtractor.hh"
#include "XrdHttpExtHandler.hh"
#include "XrdTls/XrdTls.hh"
#include "XrdTls/XrdTlsContext.hh"
#include "XrdOuc/XrdOucUtils.hh"
#include "XrdOuc/XrdOucPrivateUtils.hh"
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <vector>
#include <arpa/inet.h>
#include <sstream>
#include <cctype>
#include <fcntl.h>
#include <algorithm>
+ Include dependency graph for XrdHttpProtocol.cc:

Go to the source code of this file.

Namespaces

namespace  XrdHttpProtoInfo
 

Macros

#define HTTPS_ALERT(x, y, z)
 
#define TRACELINK   lp
 
#define TRACELINK   Link
 
#define TRACELINK   Link
 
#define TS_Xeq(x, m)   (!strcmp(x,var)) GoNo = m(Config)
 
#define TS_Xeq3(x, m)   (!strcmp(x,var)) GoNo = m(Config, extHIVec)
 
#define XRHTTP_TK_GRACETIME   600
 

Functions

void * BIO_get_data (BIO *bio)
 
int BIO_get_flags (BIO *bio)
 
int BIO_get_init (BIO *bio)
 
int BIO_get_shutdown (BIO *bio)
 
void BIO_set_data (BIO *bio, void *ptr)
 
void BIO_set_flags (BIO *bio, int flags)
 
void BIO_set_init (BIO *bio, int init)
 
void BIO_set_shutdown (BIO *bio, int shut)
 
static int BIO_XrdLink_create (BIO *bio)
 
static long BIO_XrdLink_ctrl (BIO *bio, int cmd, long num, void *ptr)
 
static int BIO_XrdLink_destroy (BIO *bio)
 
static int BIO_XrdLink_read (BIO *bio, char *data, size_t datal, size_t *read)
 
int BIO_XrdLink_write (BIO *bio, const char *data, size_t datal, size_t *written)
 
static XrdVERSIONINFODEF (compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION)
 

Variables

static const int XrdHttpProtoInfo::hsmAuto = -1
 
static const int XrdHttpProtoInfo::hsmMan = 1
 
static const int XrdHttpProtoInfo::hsmOff = 0
 
static const int XrdHttpProtoInfo::hsmOn = 1
 
int XrdHttpProtoInfo::httpsmode = hsmAuto
 
bool XrdHttpProtoInfo::httpsspec = false
 
int XrdHttpProtoInfo::tlsCache = XrdTlsContext::scOff
 
XrdTlsContextXrdHttpProtoInfo::xrdctx = 0
 
bool XrdHttpProtoInfo::xrdctxVer = false
 
const char * XrdHttpSecEntityTident = "http"
 
XrdSysTrace XrdHttpTrace ("http")
 

Macro Definition Documentation

◆ HTTPS_ALERT

#define HTTPS_ALERT (   x,
  y,
 
)
Value:
httpsspec = true;\
if (xrdctx && httpsmode == hsmAuto && (z || xrdctx->x509Verify())) \
eDest.Say("Config http." x " overrides the xrd." y " directive.")
static XrdSysError eDest(0,"crypto_")
void Say(const char *text1, const char *text2=0, const char *txt3=0, const char *text4=0, const char *text5=0, const char *txt6=0)
static const int hsmAuto
XrdTlsContext * xrdctx

Definition at line 980 of file XrdHttpProtocol.cc.

983 {
984 XrdOucEnv cfgEnv;
985 XrdOucStream Config(&eDest, getenv("XRDINSTANCE"), &cfgEnv, "=====> ");
986 std::vector<extHInfo> extHIVec;
987 char *var;
988 int cfgFD, GoNo, NoGo = 0, ismine;
989
990 var = nullptr;
991 XrdOucEnv::Import("XRD_READV_LIMITS", var);
992 XrdHttpReadRangeHandler::Configure(eDest, var, ReadRangeConfig);
993
994 pmarkHandle = (XrdNetPMark* ) myEnv->GetPtr("XrdNetPMark*");
995
996 cksumHandler.configure(xrd_cslist);
997 auto nonIanaChecksums = cksumHandler.getNonIANAConfiguredCksums();
998 if(nonIanaChecksums.size()) {
999 std::stringstream warningMsgSS;
1000 warningMsgSS << "Config warning: the following checksum algorithms are not IANA compliant: [";
1001 std::string unknownCksumString;
1002 for(auto unknownCksum: nonIanaChecksums) {
1003 unknownCksumString += unknownCksum + ",";
1004 }
1005 unknownCksumString.erase(unknownCksumString.size() - 1);
1006 warningMsgSS << unknownCksumString << "]" << ". They therefore cannot be queried by a user via HTTP." ;
1007 eDest.Say(warningMsgSS.str().c_str());
1008 }
1009
1010 // Initialize our custom BIO type.
1011 if (!m_bio_type) {
1012
1013 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1014 m_bio_type = (26|0x0400|0x0100);
1015 m_bio_method = static_cast<BIO_METHOD*>(OPENSSL_malloc(sizeof(BIO_METHOD)));
1016
1017 if (m_bio_method) {
1018 memset(m_bio_method, '\0', sizeof(BIO_METHOD));
1019 m_bio_method->type = m_bio_type;
1020 m_bio_method->bwrite = BIO_XrdLink_write;
1021 m_bio_method->bread = BIO_XrdLink_read;
1022 m_bio_method->create = BIO_XrdLink_create;
1023 m_bio_method->destroy = BIO_XrdLink_destroy;
1024 m_bio_method->ctrl = BIO_XrdLink_ctrl;
1025 }
1026 #else
1027 // OpenSSL 1.1 has an internal counter for generating unique types.
1028 // We'll switch to that when widely available.
1029 m_bio_type = BIO_get_new_index();
1030 m_bio_method = BIO_meth_new(m_bio_type, "xrdhttp-bio-method");
1031
1032 if (m_bio_method) {
1033 BIO_meth_set_write(m_bio_method, BIO_XrdLink_write);
1034 BIO_meth_set_read(m_bio_method, BIO_XrdLink_read);
1035 BIO_meth_set_create(m_bio_method, BIO_XrdLink_create);
1036 BIO_meth_set_destroy(m_bio_method, BIO_XrdLink_destroy);
1037 BIO_meth_set_ctrl(m_bio_method, BIO_XrdLink_ctrl);
1038 }
1039
1040 #endif
1041 }
1042
1043 // If we have a tls context record whether it configured for verification
1044 // so that we can provide meaningful error and warning messages.
1045 //
1047
1048 // Open and attach the config file
1049 //
1050 if ((cfgFD = open(ConfigFN, O_RDONLY, 0)) < 0)
1051 return eDest.Emsg("Config", errno, "open config file", ConfigFN);
1052 Config.Attach(cfgFD);
1053 static const char *cvec[] = { "*** http protocol config:", 0 };
1054 Config.Capture(cvec);
1055
1056 // Process items
1057 //
1058 while ((var = Config.GetMyFirstWord())) {
1059 if ((ismine = !strncmp("http.", var, 5)) && var[5]) var += 5;
1060
1061 if (ismine) {
1062 if TS_Xeq("trace", xtrace);
1063 else if TS_Xeq("cert", xsslcert);
1064 else if TS_Xeq("key", xsslkey);
1065 else if TS_Xeq("cadir", xsslcadir);
1066 else if TS_Xeq("cipherfilter", xsslcipherfilter);
1067 else if TS_Xeq("gridmap", xgmap);
1068 else if TS_Xeq("cafile", xsslcafile);
1069 else if TS_Xeq("secretkey", xsecretkey);
1070 else if TS_Xeq("desthttps", xdesthttps);
1071 else if TS_Xeq("secxtractor", xsecxtractor);
1072 else if TS_Xeq3("exthandler", xexthandler);
1073 else if TS_Xeq("selfhttps2http", xselfhttps2http);
1074 else if TS_Xeq("embeddedstatic", xembeddedstatic);
1075 else if TS_Xeq("listingredir", xlistredir);
1076 else if TS_Xeq("staticredir", xstaticredir);
1077 else if TS_Xeq("staticpreload", xstaticpreload);
1078 else if TS_Xeq("staticheader", xstaticheader);
1079 else if TS_Xeq("listingdeny", xlistdeny);
1080 else if TS_Xeq("header2cgi", xheader2cgi);
1081 else if TS_Xeq("httpsmode", xhttpsmode);
1082 else if TS_Xeq("tlsreuse", xtlsreuse);
1083 else if TS_Xeq("auth", xauth);
1084 else {
1085 eDest.Say("Config warning: ignoring unknown directive '", var, "'.");
1086 Config.Echo();
1087 continue;
1088 }
1089 if (GoNo) {
1090 Config.Echo();
1091 NoGo = 1;
1092 }
1093 }
1094 }
1095
1096// To minimize message confusion down, if an error occurred during config
1097// parsing, just bail out now with a confirming message.
1098//
1099 if (NoGo)
1100 {eDest.Say("Config failure: one or more directives are flawed!");
1101 return 1;
1102 }
1103
1104// Some headers must always be converted to CGI key=value pairs
1105//
1106 hdr2cgimap["Cache-Control"] = "cache-control";
1107
1108// Test if XrdEC is loaded
1109 if (getenv("XRDCL_EC")) usingEC = true;
1110
1111// Pre-compute the static headers
1112//
1113 const auto default_verb = m_staticheader_map.find("");
1114 std::string default_static_headers;
1115 if (default_verb != m_staticheader_map.end()) {
1116 for (const auto &header_entry : default_verb->second) {
1117 default_static_headers += header_entry.first + ": " + header_entry.second + "\r\n";
1118 }
1119 }
1120 m_staticheaders[""] = default_static_headers;
1121 for (const auto &item : m_staticheader_map) {
1122 if (item.first.empty()) {
1123 continue; // Skip default case; already handled
1124 }
1125 auto headers = default_static_headers;
1126 for (const auto &header_entry : item.second) {
1127 headers += header_entry.first + ": " + header_entry.second + "\r\n";
1128 }
1129
1130 m_staticheaders[item.first] = headers;
1131 }
1132
1133// Test if this is a caching server
1134//
1135 if (myEnv->Get("XrdCache")) hasCache = true;
1136
1137// If https was disabled, then issue a warning message if xrdtls configured
1138// of it's disabled because httpsmode was auto and xrdtls was not configured.
1139// If we get past this point then we know https is a plausible option but we
1140// can still fail if we cannot supply any missing but required options.
1141//
1142 if (httpsmode == hsmOff || (httpsmode == hsmAuto && !xrdctx && !httpsspec))
1143 {const char *why = (httpsmode == hsmOff ? "has been disabled!"
1144 : "was not configured.");
1145 const char *what = Configed();
1146
1147 eDest.Say("Config warning: HTTPS functionality ", why);
1148 httpsmode = hsmOff;
1149
1150 LoadExtHandlerNoTls(extHIVec, ConfigFN, *myEnv);
1151 if (what)
1152 {eDest.Say("Config failure: ", what, " HTTPS but it ", why);
1153 NoGo = 1;
1154 }
1155 return NoGo;
1156 }
1157
1158// Warn if a private key was specified without a cert as this has no meaning
1159// even as an auto overide as they must be paired.
1160//
1161 if (sslkey && !sslcert)
1162 {eDest.Say("Config warning: specifying http.key without http.cert "
1163 "is meaningless; ignoring key!");
1164 free(sslkey); sslkey = 0;
1165 }
1166
1167// If the mode is manual then we need to have at least a cert.
1168//
1169 if (httpsmode == hsmMan)
1170 {if (!sslcert)
1171 {eDest.Say("Config failure: 'httpsmode manual' requires atleast a "
1172 "a cert specification!");
1173 return 1;
1174 }
1175 }
1176
1177// If it's auto d through all possibilities. It's either auto with xrdtls
1178// configured or manual which needs at least a cert specification. For auto
1179// configuration we will only issue a warning if overrides were specified.
1180//
1181 if (httpsmode == hsmAuto && xrdctx)
1183 const char *what1 = 0, *what2 = 0, *what3 = 0;
1184
1185 if (!sslcert && cP->cert.size())
1186 {sslcert = strdup(cP->cert.c_str());
1187 if (cP->pkey.size()) sslkey = strdup(cP->pkey.c_str());
1188 what1 = "xrd.tls to supply 'cert' and 'key'.";
1189 }
1190 if (!sslcadir && cP->cadir.size())
1191 {sslcadir = strdup(cP->cadir.c_str());
1192 what2 = "xrd.tlsca to supply 'cadir'.";
1193 }
1194 if (!sslcafile && cP->cafile.size())
1195 {sslcafile = strdup(cP->cafile.c_str());
1196 what2 = (what2 ? "xrd.tlsca to supply 'cadir' and 'cafile'."
1197 : "xrd.tlsca to supply 'cafile'.");
1198 }
1200 crlRefIntervalSec = cP->crlRT;
1201 what3 = "xrd.tlsca to supply 'refresh' interval.";
1202 }
1203 if (!httpsspec && what1) eDest.Say("Config Using ", what1);
1204 if (!httpsspec && what2) eDest.Say("Config Using ", what2);
1205 if (!httpsspec && what3) eDest.Say("Config Using ", what3);
1206 }
1207
1208// If a gridmap or secxtractor is present then we must be able to verify certs
1209//
1210 if (!(sslcadir || sslcafile))
1211 {const char *what = Configed();
1212 const char *why = (httpsspec ? "a cadir or cafile was not specified!"
1213 : "'xrd.tlsca noverify' was specified!");
1214 if (what)
1215 {eDest.Say("Config failure: ", what, " cert verification but ", why);
1216 return 1;
1217 }
1218 }
1219 httpsmode = hsmOn;
1220
1221// Oddly we need to create an error bio at this point
1222//
1223 sslbio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
1224
1225// Now we can configure HTTPS. We will not reuse the passed context as we will
1226// be setting our own options specific to out implementation. One day we will.
1227//
1228 const char *how = "completed.";
1229 eDest.Say("++++++ HTTPS initialization started.");
1230 if (!InitTLS()) {NoGo = 1; how = "failed.";}
1231 eDest.Say("------ HTTPS initialization ", how);
1232 if (NoGo) return NoGo;
1233
1234// We can now load all the external handlers
1235//
1236 if (LoadExtHandler(extHIVec, ConfigFN, *myEnv)) return 1;
1237
1238// At this point, we can actually initialize security plugins
1239//
1240 return (InitSecurity() ? NoGo : 1);
1241}
1242
1243/******************************************************************************/
1244/* C o n f i g e d */
1245/******************************************************************************/
1246
1247const char *XrdHttpProtocol::Configed()
1248{
1249 if (secxtractor && gridmap) return "gridmap and secxtractor require";
1250 if (secxtractor) return "secxtractor requires";
1251 if (gridmap) return "gridmap requires";
1252 return 0;
1253}
1254
1255/******************************************************************************/
1256/* B u f f g e t L i n e */
1257/******************************************************************************/
1258
1260
1261int XrdHttpProtocol::BuffgetLine(XrdOucString &dest) {
1262
1263 dest = "";
1264 char save;
1265
1266 // Easy case
1267 if (myBuffEnd >= myBuffStart) {
1268 int l = 0;
1269 for (char *p = myBuffStart; p < myBuffEnd; p++) {
1270 l++;
1271 if (*p == '\n') {
1272 save = *(p+1);
1273 *(p+1) = '\0';
1274 dest.assign(myBuffStart, 0, l-1);
1275 *(p+1) = save;
1276
1277 //strncpy(dest, myBuffStart, l);
1278 //dest[l] = '\0';
1279 BuffConsume(l);
1280
1281 //if (dest[l-1] == '\n') dest[l - 1] = '\0';
1282 return l;
1283 }
1284
1285 }
1286
1287 return 0;
1288 } else {
1289 // More complex case... we have to do it in two segments
1290
1291 // Segment 1: myBuffStart->myBuff->buff+myBuff->bsize
1292 int l = 0;
1293 for (char *p = myBuffStart; p < myBuff->buff + myBuff->bsize; p++) {
1294 l++;
1295 if ((*p == '\n') || (*p == '\0')) {
1296 save = *(p+1);
1297 *(p+1) = '\0';
1298 dest.assign(myBuffStart, 0, l-1);
1299 *(p+1) = save;
1300
1301 //strncpy(dest, myBuffStart, l);
1302
1303 BuffConsume(l);
1304
1305 //if (dest[l-1] == '\n') dest[l - 1] = '\0';
1306 return l;
1307 }
1308
1309 }
1310
1311 // We did not find the \n, let's keep on searching in the 2nd segment
1312 // Segment 2: myBuff->buff --> myBuffEnd
1313 l = 0;
1314 for (char *p = myBuff->buff; p < myBuffEnd; p++) {
1315 l++;
1316 if ((*p == '\n') || (*p == '\0')) {
1317 save = *(p+1);
1318 *(p+1) = '\0';
1319 // Remember the 1st segment
1320 int l1 = myBuff->buff + myBuff->bsize - myBuffStart;
1321
1322 dest.assign(myBuffStart, 0, l1-1);
1323 //strncpy(dest, myBuffStart, l1);
1324 BuffConsume(l1);
1325
1326 dest.insert(myBuffStart, l1, l-1);
1327 //strncpy(dest + l1, myBuffStart, l);
1328 //dest[l + l1] = '\0';
1329 BuffConsume(l);
1330
1331 *(p+1) = save;
1332
1333 //if (dest[l + l1 - 1] == '\n') dest[l + l1 - 1] = '\0';
1334 return l + l1;
1335 }
1336
1337 }
1338
1339
1340
1341 }
1342
1343 return 0;
1344}
1345
1346/******************************************************************************/
1347/* g e t D a t a O n e S h o t */
1348/******************************************************************************/
1349
1350int XrdHttpProtocol::getDataOneShot(int blen, bool wait) {
1351 int rlen, maxread;
1352
1353 // Get up to blen bytes from the connection. Put them into mybuff.
1354 // This primitive, for the way it is used, is not supposed to block if wait=false
1355
1356 // Returns:
1357 // 2: no space left in buffer
1358 // 1: timeout
1359 // -1: error
1360 // 0: everything read correctly
1361
1362
1363
1364 // Check for buffer overflow first
1365 maxread = std::min(blen, BuffAvailable());
1366 TRACE(DEBUG, "getDataOneShot BuffAvailable: " << BuffAvailable() << " maxread: " << maxread);
1367
1368 if (!maxread)
1369 return 2;
1370
1371 if (ishttps) {
1372 int sslavail = maxread;
1373
1374 if (!wait) {
1375 int l = SSL_pending(ssl);
1376 if (l > 0)
1377 sslavail = std::min(maxread, SSL_pending(ssl));
1378 }
1379
1380 if (sslavail < 0) {
1381 Link->setEtext("link SSL_pending error");
1382 ERR_print_errors(sslbio_err);
1383 return -1;
1384 }
1385
1386 TRACE(DEBUG, "getDataOneShot sslavail: " << sslavail);
1387 if (sslavail <= 0) return 0;
1388
1389 if (myBuffEnd - myBuff->buff >= myBuff->bsize) {
1390 TRACE(DEBUG, "getDataOneShot Buffer panic");
1391 myBuffEnd = myBuff->buff;
1392 }
1393
1394 rlen = SSL_read(ssl, myBuffEnd, sslavail);
1395 if (rlen <= 0) {
1396 Link->setEtext("link SSL read error");
1397 ERR_print_errors(sslbio_err);
1398 return -1;
1399 }
1400
1401
1402 } else {
1403
1404 if (myBuffEnd - myBuff->buff >= myBuff->bsize) {
1405 TRACE(DEBUG, "getDataOneShot Buffer panic");
1406 myBuffEnd = myBuff->buff;
1407 }
1408
1409 if (wait)
1410 rlen = Link->Recv(myBuffEnd, maxread, readWait);
1411 else
1412 rlen = Link->Recv(myBuffEnd, maxread);
1413
1414
1415 if (rlen == 0) {
1416 Link->setEtext("link read error or closed");
1417 return -1;
1418 }
1419
1420 if (rlen < 0) {
1421 Link->setEtext("link timeout or other error");
1422 return -1;
1423 }
1424 }
1425
1426 myBuffEnd += rlen;
1427
1428 TRACE(REQ, "read " << rlen << " of " << blen << " bytes");
1429
1430 return 0;
1431}
1432
1434
1435int XrdHttpProtocol::BuffAvailable() {
1436 int r;
1437
1438 if (myBuffEnd >= myBuffStart)
1439 r = myBuff->buff + myBuff->bsize - myBuffEnd;
1440 else
1441 r = myBuffStart - myBuffEnd;
1442
1443 if ((r < 0) || (r > myBuff->bsize)) {
1444 TRACE(REQ, "internal error, myBuffAvailable: " << r << " myBuff->bsize " << myBuff->bsize);
1445 abort();
1446 }
1447
1448 return r;
1449}
1450
1451/******************************************************************************/
1452/* B u f f U s e d */
1453/******************************************************************************/
1454
1456
1457int XrdHttpProtocol::BuffUsed() {
1458 int r;
1459
1460 if (myBuffEnd >= myBuffStart)
1461 r = myBuffEnd - myBuffStart;
1462 else
1463
1464 r = myBuff->bsize - (myBuffStart - myBuffEnd);
1465
1466 if ((r < 0) || (r > myBuff->bsize)) {
1467 TRACE(REQ, "internal error, myBuffUsed: " << r << " myBuff->bsize " << myBuff->bsize);
1468 abort();
1469 }
1470
1471 return r;
1472}
1473
1474/******************************************************************************/
1475/* B u f f F r e e */
1476/******************************************************************************/
1477
1479
1480int XrdHttpProtocol::BuffFree() {
1481 return (myBuff->bsize - BuffUsed());
1482}
1483
1484/******************************************************************************/
1485/* B u f f C o n s u m e */
1486/******************************************************************************/
1487
1488void XrdHttpProtocol::BuffConsume(int blen) {
1489
1490 if (blen > myBuff->bsize) {
1491 TRACE(REQ, "internal error, BuffConsume(" << blen << ") smaller than buffsize");
1492 abort();
1493 }
1494
1495 if (blen > BuffUsed()) {
1496 TRACE(REQ, "internal error, BuffConsume(" << blen << ") larger than BuffUsed:" << BuffUsed());
1497 abort();
1498 }
1499
1500 myBuffStart = myBuffStart + blen;
1501
1502 if (myBuffStart >= myBuff->buff + myBuff->bsize)
1503 myBuffStart -= myBuff->bsize;
1504
1505 if (myBuffEnd >= myBuff->buff + myBuff->bsize)
1506 myBuffEnd -= myBuff->bsize;
1507
1508 if (BuffUsed() == 0)
1509 myBuffStart = myBuffEnd = myBuff->buff;
1510}
1511
1512/******************************************************************************/
1513/* B u f f g e t D a t a */
1514/******************************************************************************/
1515
1524int XrdHttpProtocol::BuffgetData(int blen, char **data, bool wait) {
1525 int rlen;
1526
1527 TRACE(DEBUG, "BuffgetData: requested " << blen << " bytes");
1528
1529
1530 if (wait) {
1531 // If there's not enough data in the buffer then wait on the socket until it comes
1532 if (blen > BuffUsed()) {
1533 TRACE(REQ, "BuffgetData: need to read " << blen - BuffUsed() << " bytes");
1534 if ( getDataOneShot(blen - BuffUsed(), true) )
1535 // The wanted data could not be read. Either timeout of connection closed
1536 return 0;
1537 }
1538 } else {
1539 // Get a peek at the socket, without waiting, if we have no data in the buffer
1540 if ( !BuffUsed() ) {
1541 if ( getDataOneShot(blen, false) )
1542 // The wanted data could not be read. Either timeout of connection closed
1543 return -1;
1544 }
1545 }
1546
1547 // And now make available the data taken from the buffer. Note that the buffer
1548 // may be empty...
1549 if (myBuffStart <= myBuffEnd) {
1550 rlen = std::min( (long) blen, (long)(myBuffEnd - myBuffStart) );
1551
1552 } else
1553 rlen = std::min( (long) blen, (long)(myBuff->buff + myBuff->bsize - myBuffStart) );
1554
1555 *data = myBuffStart;
1556 BuffConsume(rlen);
1557 return rlen;
1558}
1559
1560/******************************************************************************/
1561/* S e n d D a t a */
1562/******************************************************************************/
1563
1565
1566int XrdHttpProtocol::SendData(const char *body, int bodylen) {
1567
1568 int r;
1569
1570 if (body && bodylen) {
1571 TRACE(REQ, "Sending " << bodylen << " bytes");
1572 if (ishttps) {
1573 r = SSL_write(ssl, body, bodylen);
1574 if (r <= 0) {
1575 ERR_print_errors(sslbio_err);
1576 return -1;
1577 }
1578
1579 } else {
1580 r = Link->Send(body, bodylen);
1581 if (r <= 0) return -1;
1582 }
1583 }
1584
1585 return 0;
1586}
1587
1588/******************************************************************************/
1589/* S t a r t S i m p l e R e s p */
1590/******************************************************************************/
1591
1592int XrdHttpProtocol::StartSimpleResp(int code, const char *desc, const char *header_to_add, long long bodylen, bool keepalive) {
1593 std::stringstream ss;
1594 const std::string crlf = "\r\n";
1595
1596 ss << "HTTP/1.1 " << code << " ";
1597 if (desc) {
1598 ss << desc;
1599 } else {
1600 if (code == 200) ss << "OK";
1601 else if (code == 100) ss << "Continue";
1602 else if (code == 206) ss << "Partial Content";
1603 else if (code == 302) ss << "Redirect";
1604 else if (code == 307) ss << "Temporary Redirect";
1605 else if (code == 400) ss << "Bad Request";
1606 else if (code == 403) ss << "Forbidden";
1607 else if (code == 404) ss << "Not Found";
1608 else if (code == 405) ss << "Method Not Allowed";
1609 else if (code == 416) ss << "Range Not Satisfiable";
1610 else if (code == 500) ss << "Internal Server Error";
1611 else if (code == 502) ss << "Bad Gateway";
1612 else if (code == 504) ss << "Gateway Timeout";
1613 else ss << "Unknown";
1614 }
1615 ss << crlf;
1616 if (keepalive && (code != 100))
1617 ss << "Connection: Keep-Alive" << crlf;
1618 else
1619 ss << "Connection: Close" << crlf;
1620
1621 ss << "Server: XrootD/" << XrdVSTRING << crlf;
1622
1623 const auto iter = m_staticheaders.find(CurrentReq.requestverb);
1624 if (iter != m_staticheaders.end()) {
1625 ss << iter->second;
1626 } else {
1627 ss << m_staticheaders[""];
1628 }
1629
1630 if ((bodylen >= 0) && (code != 100))
1631 ss << "Content-Length: " << bodylen << crlf;
1632
1633 if (header_to_add && (header_to_add[0] != '\0'))
1634 ss << header_to_add << crlf;
1635
1636 ss << crlf;
1637
1638 const std::string &outhdr = ss.str();
1639 TRACEI(RSP, "Sending resp: " << code << " header len:" << outhdr.size());
1640 if (SendData(outhdr.c_str(), outhdr.size()))
1641 return -1;
1642
1643 return 0;
1644}
1645
1646/******************************************************************************/
1647/* S t a r t C h u n k e d R e s p */
1648/******************************************************************************/
1649
1650int XrdHttpProtocol::StartChunkedResp(int code, const char *desc, const char *header_to_add, long long bodylen, bool keepalive) {
1651 const std::string crlf = "\r\n";
1652 std::stringstream ss;
1653
1654 if (header_to_add && (header_to_add[0] != '\0')) {
1655 ss << header_to_add << crlf;
1656 }
1657
1658 ss << "Transfer-Encoding: chunked";
1659 TRACEI(RSP, "Starting chunked response");
1660 return StartSimpleResp(code, desc, ss.str().c_str(), bodylen, keepalive);
1661}
1662
1663/******************************************************************************/
1664/* C h u n k R e s p */
1665/******************************************************************************/
1666
1667int XrdHttpProtocol::ChunkResp(const char *body, long long bodylen) {
1668 long long content_length = (bodylen <= 0) ? (body ? strlen(body) : 0) : bodylen;
1669 if (ChunkRespHeader(content_length))
1670 return -1;
1671
1672 if (body && SendData(body, content_length))
1673 return -1;
1674
1675 return ChunkRespFooter();
1676}
1677
1678/******************************************************************************/
1679/* C h u n k R e s p H e a d e r */
1680/******************************************************************************/
1681
1682int XrdHttpProtocol::ChunkRespHeader(long long bodylen) {
1683 const std::string crlf = "\r\n";
1684 std::stringstream ss;
1685
1686 ss << std::hex << bodylen << std::dec << crlf;
1687
1688 const std::string &chunkhdr = ss.str();
1689 TRACEI(RSP, "Sending encoded chunk of size " << bodylen);
1690 return (SendData(chunkhdr.c_str(), chunkhdr.size())) ? -1 : 0;
1691}
1692
1693/******************************************************************************/
1694/* C h u n k R e s p F o o t e r */
1695/******************************************************************************/
1696
1697int XrdHttpProtocol::ChunkRespFooter() {
1698 const std::string crlf = "\r\n";
1699 return (SendData(crlf.c_str(), crlf.size())) ? -1 : 0;
1700}
1701
1702/******************************************************************************/
1703/* S e n d S i m p l e R e s p */
1704/******************************************************************************/
1705
1709
1710int XrdHttpProtocol::SendSimpleResp(int code, const char *desc, const char *header_to_add, const char *body, long long bodylen, bool keepalive) {
1711
1712 long long content_length = bodylen;
1713 if (bodylen <= 0) {
1714 content_length = body ? strlen(body) : 0;
1715 }
1716
1717 if (StartSimpleResp(code, desc, header_to_add, content_length, keepalive) < 0)
1718 return -1;
1719
1720 //
1721 // Send the data
1722 //
1723 if (body)
1724 return SendData(body, content_length);
1725
1726 return 0;
1727}
1728
1729/******************************************************************************/
1730/* C o n f i g u r e */
1731/******************************************************************************/
1732
1733int XrdHttpProtocol::Configure(char *parms, XrdProtocol_Config * pi) {
1734 /*
1735 Function: Establish configuration at load time.
1736
1737 Input: None.
1738
1739 Output: 0 upon success or !0 otherwise.
1740 */
1741
1742 char *rdf;
1743
1744 // Copy out the special info we want to use at top level
1745 //
1746 eDest.logger(pi->eDest->logger());
1748 // SI = new XrdXrootdStats(pi->Stats);
1749 Sched = pi->Sched;
1750 BPool = pi->BPool;
1751 xrd_cslist = getenv("XRD_CSLIST");
1752
1753 Port = pi->Port;
1754
1755 // Copy out the current TLS context
1756 //
1757 xrdctx = pi->tlsCtx;
1758
1759 {
1760 char buf[16];
1761 sprintf(buf, "%d", Port);
1762 Port_str = strdup(buf);
1763 }
1764
1765 // Now process and configuration parameters
1766 //
1767 rdf = (parms && *parms ? parms : pi->ConfigFN);
1768 if (rdf && Config(rdf, pi->theEnv)) return 0;
1770
1771 // Set the redirect flag if we are a pure redirector
1773 if ((rdf = getenv("XRDROLE"))) {
1774 eDest.Emsg("Config", "XRDROLE: ", rdf);
1775
1776 if (!strcasecmp(rdf, "manager") || !strcasecmp(rdf, "supervisor")) {
1778 eDest.Emsg("Config", "Configured as HTTP(s) redirector.");
1779 } else {
1780
1781 eDest.Emsg("Config", "Configured as HTTP(s) data server.");
1782 }
1783
1784 } else {
1785 eDest.Emsg("Config", "No XRDROLE specified.");
1786 }
1787
1788 // Schedule protocol object cleanup
1789 //
1792 ProtStack.Set((pi->ConnMax / 3 ? pi->ConnMax / 3 : 30), 60 * 60);
1793
1794 // Return success
1795 //
1796
1797 return 1;
1798}
1799
1800/******************************************************************************/
1801/* p a r s e H e a d e r 2 C G I */
1802/******************************************************************************/
1803int XrdHttpProtocol::parseHeader2CGI(XrdOucStream &Config, XrdSysError & err,std::map<std::string, std::string> &header2cgi) {
1804 char *val, keybuf[1024], parmbuf[1024];
1805 char *parm;
1806
1807 // Get the header key
1808 val = Config.GetWord();
1809 if (!val || !val[0]) {
1810 err.Emsg("Config", "No headerkey specified.");
1811 return 1;
1812 } else {
1813
1814 // Trim the beginning, in place
1815 while ( *val && !isalnum(*val) ) val++;
1816 strcpy(keybuf, val);
1817
1818 // Trim the end, in place
1819 char *pp;
1820 pp = keybuf + strlen(keybuf) - 1;
1821 while ( (pp >= keybuf) && (!isalnum(*pp)) ) {
1822 *pp = '\0';
1823 pp--;
1824 }
1825
1826 parm = Config.GetWord();
1827
1828 // Avoids segfault in case a key is given without value
1829 if(!parm || !parm[0]) {
1830 err.Emsg("Config", "No header2cgi value specified. key: '", keybuf, "'");
1831 return 1;
1832 }
1833
1834 // Trim the beginning, in place
1835 while ( *parm && !isalnum(*parm) ) parm++;
1836 strcpy(parmbuf, parm);
1837
1838 // Trim the end, in place
1839 pp = parmbuf + strlen(parmbuf) - 1;
1840 while ( (pp >= parmbuf) && (!isalnum(*pp)) ) {
1841 *pp = '\0';
1842 pp--;
1843 }
1844
1845 // Add this mapping to the map that will be used
1846 try {
1847 header2cgi[keybuf] = parmbuf;
1848 } catch ( ... ) {
1849 err.Emsg("Config", "Can't insert new header2cgi rule. key: '", keybuf, "'");
1850 return 1;
1851 }
1852
1853 }
1854 return 0;
1855}
1856
1857
1858/******************************************************************************/
1859/* I n i t T L S */
1860/******************************************************************************/
1861
1862bool XrdHttpProtocol::InitTLS() {
1863
1864 std::string eMsg;
1867
1868// Create a new TLS context
1869//
1870 if (sslverifydepth > 255) sslverifydepth = 255;
1872 //TLS_SET_REFINT will set the refresh interval in minutes, hence the division by 60
1875
1876// Make sure the context was created
1877//
1878 if (!xrdctx->isOK())
1879 {eDest.Say("Config failure: ", eMsg.c_str());
1880 return false;
1881 }
1882
1883// Setup session cache (this is controversial). The default is off but many
1884// programs expect it being enabled and break when it is disabled. In such
1885// cases it should be enabled. This is, of course, a big OpenSSL mess.
1886//
1887 static const char *sess_ctx_id = "XrdHTTPSessionCtx";
1888 unsigned int n =(unsigned int)(strlen(sess_ctx_id)+1);
1889 xrdctx->SessionCache(tlsCache, sess_ctx_id, n);
1890
1891// Set special ciphers if so specified.
1892//
1894 {eDest.Say("Config failure: ", "Unable to set allowable https ciphers!");
1895 return false;
1896 }
1897
1898// All done
1899//
1900 return true;
1901}
1902
1903/******************************************************************************/
1904/* C l e a n u p */
1905/******************************************************************************/
1906
1907void XrdHttpProtocol::Cleanup() {
1908
1909 TRACE(ALL, " Cleanup");
1910
1911 if (BPool && myBuff) {
1912 BuffConsume(BuffUsed());
1913 BPool->Release(myBuff);
1914 myBuff = 0;
1915 }
1916
1917 if (ssl) {
1918 // Shutdown the SSL/TLS connection
1919 // https://www.openssl.org/docs/man1.0.2/man3/SSL_shutdown.html
1920 // We don't need a bidirectional shutdown as
1921 // when we are here, the connection will not be re-used.
1922 // In the case SSL_shutdown returns 0,
1923 // "the output of SSL_get_error(3) may be misleading, as an erroneous SSL_ERROR_SYSCALL may be flagged even though no error occurred."
1924 // we will then just flush the thread's queue.
1925 // In the case an error really happened, we print the error that happened
1926 int ret = SSL_shutdown(ssl);
1927 if (ret != 1) {
1928 if(ret == 0) {
1929 // Clean this thread's error queue for the old openssl versions
1930 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1931 ERR_remove_thread_state(nullptr);
1932 #endif
1933 } else {
1934 //ret < 0, an error really happened.
1935 TRACE(ALL, " SSL_shutdown failed");
1936 ERR_print_errors(sslbio_err);
1937 }
1938 }
1939
1940 if (secxtractor)
1941 secxtractor->FreeSSL(ssl);
1942
1943 SSL_free(ssl);
1944
1945 }
1946
1947
1948 ssl = 0;
1949 sbio = 0;
1950
1951 if (SecEntity.caps) free(SecEntity.caps);
1952 if (SecEntity.grps) free(SecEntity.grps);
1954 if (SecEntity.vorg) free(SecEntity.vorg);
1955 if (SecEntity.role) free(SecEntity.role);
1956 if (SecEntity.name) free(SecEntity.name);
1957 if (SecEntity.host) free(SecEntity.host);
1959
1960 SecEntity.Reset();
1961
1962 if (Addr_str) free(Addr_str);
1963 Addr_str = 0;
1964}
1965
1966/******************************************************************************/
1967/* R e s e t */
1968/******************************************************************************/
1969
1970void XrdHttpProtocol::Reset() {
1971
1972 TRACE(ALL, " Reset");
1973 Link = 0;
1974 CurrentReq.reset();
1975 CurrentReq.reqstate = 0;
1976
1977 if (myBuff) {
1978 BPool->Release(myBuff);
1979 myBuff = 0;
1980 }
1981 myBuffStart = myBuffEnd = 0;
1982
1983 DoingLogin = false;
1984 DoneSetInfo = false;
1985
1986 ResumeBytes = 0;
1987 Resume = 0;
1988
1989 //
1990 // numReads = 0;
1991 // numReadP = 0;
1992 // numReadV = 0;
1993 // numSegsV = 0;
1994 // numWrites = 0;
1995 // numFiles = 0;
1996 // cumReads = 0;
1997 // cumReadV = 0;
1998 // cumSegsV = 0;
1999 // cumWrites = 0;
2000 // totReadP = 0;
2001
2002 SecEntity.Reset();
2004 ishttps = false;
2005 ssldone = false;
2006
2007 Bridge = 0;
2008 ssl = 0;
2009 sbio = 0;
2010
2011}
2012
2013/******************************************************************************/
2014/* x h t t p s m o d e */
2015/******************************************************************************/
2016
2017/* Function: xhttpsmode
2018
2019 Purpose: To parse the directive: httpsmode {auto | disable | manual}
2020
2021 auto configure https if configured in xrd framework.
2022 disable do not configure https no matter what
2023 manual configure https and ignore the xrd framework
2024
2025 Output: 0 upon success or !0 upon failure.
2026 */
2027
2028int XrdHttpProtocol::xhttpsmode(XrdOucStream & Config) {
2029 char *val;
2030
2031 // Get the val
2032 //
2033 val = Config.GetWord();
2034 if (!val || !val[0]) {
2035 eDest.Emsg("Config", "httpsmode parameter not specified");
2036 return 1;
2037 }
2038
2039 // Record the val
2040 //
2041 if (!strcmp(val, "auto")) httpsmode = hsmAuto;
2042 else if (!strcmp(val, "disable")) httpsmode = hsmOff;
2043 else if (!strcmp(val, "manual")) httpsmode = hsmMan;
2044 else {eDest.Emsg("Config", "invalid httpsmode parameter - ", val);
2045 return 1;
2046 }
2047 return 0;
2048}
2049
2050/******************************************************************************/
2051/* x s s l v e r i f y d e p t h */
2052/******************************************************************************/
2053
2054/* Function: xsslverifydepth
2055
2056 Purpose: To parse the directive: sslverifydepth <depth>
2057
2058 <depth> the max depth of the ssl cert verification
2059
2060 Output: 0 upon success or !0 upon failure.
2061 */
2062
2063int XrdHttpProtocol::xsslverifydepth(XrdOucStream & Config) {
2064 char *val;
2065
2066 // Get the val
2067 //
2068 val = Config.GetWord();
2069 if (!val || !val[0]) {
2070 eDest.Emsg("Config", "sslverifydepth value not specified");
2071 return 1;
2072 }
2073
2074 // Record the val
2075 //
2076 sslverifydepth = atoi(val);
2077
2078 if (xrdctxVer){ HTTPS_ALERT("verifydepth","tlsca",false); }
2079 return 0;
2080}
2081
2082/******************************************************************************/
2083/* x s s l c e r t */
2084/******************************************************************************/
2085
2086/* Function: xsslcert
2087
2088 Purpose: To parse the directive: sslcert <path>
2089
2090 <path> the path of the server certificate to be used.
2091
2092 Output: 0 upon success or !0 upon failure.
2093 */
2094
2095int XrdHttpProtocol::xsslcert(XrdOucStream & Config) {
2096 char *val;
2097
2098 // Get the path
2099 //
2100 val = Config.GetWord();
2101 if (!val || !val[0]) {
2102 eDest.Emsg("Config", "HTTP X509 certificate not specified");
2103 return 1;
2104 }
2105
2106 // Record the path
2107 //
2108 if (sslcert) free(sslcert);
2109 sslcert = strdup(val);
2110
2111 // If we have an xrd context issue reminder
2112 //
2113 HTTPS_ALERT("cert","tls",true);
2114 return 0;
2115}
2116
2117/******************************************************************************/
2118/* x s s l k e y */
2119/******************************************************************************/
2120
2121/* Function: xsslkey
2122
2123 Purpose: To parse the directive: sslkey <path>
2124
2125 <path> the path of the server key to be used.
2126
2127 Output: 0 upon success or !0 upon failure.
2128 */
2129
2130int XrdHttpProtocol::xsslkey(XrdOucStream & Config) {
2131 char *val;
2132
2133 // Get the path
2134 //
2135 val = Config.GetWord();
2136 if (!val || !val[0]) {
2137 eDest.Emsg("Config", "HTTP X509 key not specified");
2138 return 1;
2139 }
2140
2141 // Record the path
2142 //
2143 if (sslkey) free(sslkey);
2144 sslkey = strdup(val);
2145
2146 HTTPS_ALERT("key","tls",true);
2147 return 0;
2148}
2149
2150/******************************************************************************/
2151/* x g m a p */
2152/******************************************************************************/
2153
2154/* Function: xgmap
2155
2156 Purpose: To parse the directive: gridmap [required] [compatNameGeneration] <path>
2157
2158 required optional parameter which if present treats any grimap errors
2159 as fatal.
2160 <path> the path of the gridmap file to be used. Normally it's
2161 /etc/grid-security/gridmap. No mapfile means no translation
2162 required. Pointing to a non existing mapfile is an error.
2163
2164 Output: 0 upon success or !0 upon failure.
2165 */
2166
2167int XrdHttpProtocol::xgmap(XrdOucStream & Config) {
2168 char *val;
2169
2170 // Get the path
2171 //
2172 val = Config.GetWord();
2173 if (!val || !val[0]) {
2174 eDest.Emsg("Config", "HTTP X509 gridmap file location not specified");
2175 return 1;
2176 }
2177
2178 // Handle optional parameter "required"
2179 //
2180 if (!strncmp(val, "required", 8)) {
2181 isRequiredGridmap = true;
2182 val = Config.GetWord();
2183
2184 if (!val || !val[0]) {
2185 eDest.Emsg("Config", "HTTP X509 gridmap file missing after [required] "
2186 "parameter");
2187 return 1;
2188 }
2189 }
2190
2191 // Handle optional parameter "compatNameGeneration"
2192 //
2193 if (!strcmp(val, "compatNameGeneration")) {
2194 compatNameGeneration = true;
2195 val = Config.GetWord();
2196 if (!val || !val[0]) {
2197 eDest.Emsg("Config", "HTTP X509 gridmap file missing after "
2198 "[compatNameGeneration] parameter");
2199 return 1;
2200 }
2201 }
2202
2203
2204 // Record the path
2205 //
2206 if (gridmap) free(gridmap);
2207 gridmap = strdup(val);
2208 return 0;
2209}
2210
2211/******************************************************************************/
2212/* x s s l c a f i l e */
2213/******************************************************************************/
2214
2215/* Function: xsslcafile
2216
2217 Purpose: To parse the directive: sslcafile <path>
2218
2219 <path> the path of the server key to be used.
2220
2221 Output: 0 upon success or !0 upon failure.
2222 */
2223
2224int XrdHttpProtocol::xsslcafile(XrdOucStream & Config) {
2225 char *val;
2226
2227 // Get the path
2228 //
2229 val = Config.GetWord();
2230 if (!val || !val[0]) {
2231 eDest.Emsg("Config", "HTTP X509 CAfile not specified");
2232 return 1;
2233 }
2234
2235 // Record the path
2236 //
2237 if (sslcafile) free(sslcafile);
2238 sslcafile = strdup(val);
2239
2240 if (xrdctxVer){ HTTPS_ALERT("cafile","tlsca",false); }
2241 return 0;
2242}
2243
2244/******************************************************************************/
2245/* x s e c r e t k e y */
2246/******************************************************************************/
2247
2248/* Function: xsecretkey
2249
2250 Purpose: To parse the directive: xsecretkey <key>
2251
2252 <key> the key to be used
2253
2254 Output: 0 upon success or !0 upon failure.
2255 */
2256
2257int XrdHttpProtocol::xsecretkey(XrdOucStream & Config) {
2258 char *val;
2259 bool inFile = false;
2260
2261 // Get the path
2262 //
2263 val = Config.GetWord();
2264 if (!val || !val[0]) {
2265 eDest.Emsg("Config", "Shared secret key not specified");
2266 return 1;
2267 }
2268
2269
2270 // If the token starts with a slash, then we interpret it as
2271 // the path to a file that contains the secretkey
2272 // otherwise, the token itself is the secretkey
2273 if (val[0] == '/') {
2274 struct stat st;
2275 inFile = true;
2276 int fd = open(val, O_RDONLY);
2277
2278 if ( fd == -1 ) {
2279 eDest.Emsg("Config", errno, "open shared secret key file", val);
2280 return 1;
2281 }
2282
2283 if ( fstat(fd, &st) != 0 ) {
2284 eDest.Emsg("Config", errno, "fstat shared secret key file", val);
2285 close(fd);
2286 return 1;
2287 }
2288
2289 if ( st.st_mode & S_IWOTH & S_IWGRP & S_IROTH) {
2290 eDest.Emsg("Config",
2291 "For your own security, the shared secret key file cannot be world readable or group writable '", val, "'");
2292 close(fd);
2293 return 1;
2294 }
2295
2296 FILE *fp = fdopen(fd, "r");
2297
2298 if ( fp == nullptr ) {
2299 eDest.Emsg("Config", errno, "fdopen shared secret key file", val);
2300 close(fd);
2301 return 1;
2302 }
2303
2304 char line[1024];
2305 while( fgets(line, 1024, fp) ) {
2306 char *pp;
2307
2308 // Trim the end
2309 pp = line + strlen(line) - 1;
2310 while ( (pp >= line) && (!isalnum(*pp)) ) {
2311 *pp = '\0';
2312 pp--;
2313 }
2314
2315 // Trim the beginning
2316 pp = line;
2317 while ( *pp && !isalnum(*pp) ) pp++;
2318
2319 if ( strlen(pp) >= 32 ) {
2320 eDest.Say("Config", "Secret key loaded.");
2321 // Record the path
2322 if (secretkey) free(secretkey);
2323 secretkey = strdup(pp);
2324
2325 fclose(fp);
2326 return 0;
2327 }
2328
2329 }
2330
2331 fclose(fp);
2332 eDest.Emsg("Config", "Cannot find useful secretkey in file '", val, "'");
2333 return 1;
2334
2335 }
2336
2337 if ( strlen(val) < 32 ) {
2338 eDest.Emsg("Config", "Secret key is too short");
2339 return 1;
2340 }
2341
2342 // Record the path
2343 if (secretkey) free(secretkey);
2344 secretkey = strdup(val);
2345 if (!inFile) Config.noEcho();
2346
2347 return 0;
2348}
2349
2350/******************************************************************************/
2351/* x l i s t d e n y */
2352/******************************************************************************/
2353
2354/* Function: xlistdeny
2355
2356 Purpose: To parse the directive: listingdeny <yes|no|0|1>
2357
2358 <val> makes this redirector deny listings with an error
2359
2360 Output: 0 upon success or !0 upon failure.
2361 */
2362
2363int XrdHttpProtocol::xlistdeny(XrdOucStream & Config) {
2364 char *val;
2365
2366 // Get the path
2367 //
2368 val = Config.GetWord();
2369 if (!val || !val[0]) {
2370 eDest.Emsg("Config", "listingdeny flag not specified");
2371 return 1;
2372 }
2373
2374 // Record the value
2375 //
2376 listdeny = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2377
2378
2379 return 0;
2380}
2381
2382/******************************************************************************/
2383/* x l i s t r e d i r */
2384/******************************************************************************/
2385
2386/* Function: xlistredir
2387
2388 Purpose: To parse the directive: listingredir <Url>
2389
2390 <Url> http/https server to redirect to in the case of listing
2391
2392 Output: 0 upon success or !0 upon failure.
2393 */
2394
2395int XrdHttpProtocol::xlistredir(XrdOucStream & Config) {
2396 char *val;
2397
2398 // Get the path
2399 //
2400 val = Config.GetWord();
2401 if (!val || !val[0]) {
2402 eDest.Emsg("Config", "listingredir flag not specified");
2403 return 1;
2404 }
2405
2406 // Record the value
2407 //
2408 if (listredir) free(listredir);
2409 listredir = strdup(val);
2410
2411
2412 return 0;
2413}
2414
2415/******************************************************************************/
2416/* x s s l d e s t h t t p s */
2417/******************************************************************************/
2418
2419/* Function: xdesthttps
2420
2421 Purpose: To parse the directive: desthttps <yes|no|0|1>
2422
2423 <val> makes this redirector produce http or https redirection targets
2424
2425 Output: 0 upon success or !0 upon failure.
2426 */
2427
2428int XrdHttpProtocol::xdesthttps(XrdOucStream & Config) {
2429 char *val;
2430
2431 // Get the path
2432 //
2433 val = Config.GetWord();
2434 if (!val || !val[0]) {
2435 eDest.Emsg("Config", "desthttps flag not specified");
2436 return 1;
2437 }
2438
2439 // Record the value
2440 //
2441 isdesthttps = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2442
2443
2444 return 0;
2445}
2446
2447/******************************************************************************/
2448/* x e m b e d d e d s t a t i c */
2449/******************************************************************************/
2450
2451/* Function: xembeddedstatic
2452
2453 Purpose: To parse the directive: embeddedstatic <yes|no|0|1|true|false>
2454
2455 <val> this server will redirect HTTPS to itself using HTTP+token
2456
2457 Output: 0 upon success or !0 upon failure.
2458 */
2459
2460int XrdHttpProtocol::xembeddedstatic(XrdOucStream & Config) {
2461 char *val;
2462
2463 // Get the path
2464 //
2465 val = Config.GetWord();
2466 if (!val || !val[0]) {
2467 eDest.Emsg("Config", "embeddedstatic flag not specified");
2468 return 1;
2469 }
2470
2471 // Record the value
2472 //
2473 embeddedstatic = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2474
2475
2476 return 0;
2477}
2478
2479/******************************************************************************/
2480/* x r e d i r s t a t i c */
2481/******************************************************************************/
2482
2483/* Function: xstaticredir
2484
2485 Purpose: To parse the directive: staticredir <Url>
2486
2487 <Url> http/https server to redirect to in the case of /static
2488
2489 Output: 0 upon success or !0 upon failure.
2490 */
2491
2492int XrdHttpProtocol::xstaticredir(XrdOucStream & Config) {
2493 char *val;
2494
2495 // Get the path
2496 //
2497 val = Config.GetWord();
2498 if (!val || !val[0]) {
2499 eDest.Emsg("Config", "staticredir url not specified");
2500 return 1;
2501 }
2502
2503 // Record the value
2504 //
2505 if (staticredir) free(staticredir);
2506 staticredir = strdup(val);
2507
2508 return 0;
2509}
2510
2511/******************************************************************************/
2512/* x p r e l o a d s t a t i c */
2513/******************************************************************************/
2514
2515/* Function: xpreloadstatic
2516
2517 Purpose: To parse the directive: preloadstatic <http url path> <local file>
2518
2519 <http url path> http/http path whose response we are preloading
2520 e.g. /static/mycss.css
2521 NOTE: this must start with /static
2522
2523
2524 Output: 0 upon success or !0 upon failure.
2525 */
2526
2527int XrdHttpProtocol::xstaticpreload(XrdOucStream & Config) {
2528 char *val, *k, key[1024];
2529
2530 // Get the key
2531 //
2532 k = Config.GetWord();
2533 if (!k || !k[0]) {
2534 eDest.Emsg("Config", "preloadstatic urlpath not specified");
2535 return 1;
2536 }
2537
2538 strcpy(key, k);
2539
2540 // Get the val
2541 //
2542 val = Config.GetWord();
2543 if (!val || !val[0]) {
2544 eDest.Emsg("Config", "preloadstatic filename not specified");
2545 return 1;
2546 }
2547
2548 // Try to load the file into memory
2549 int fp = open(val, O_RDONLY);
2550 if( fp < 0 ) {
2551 eDest.Emsg("Config", errno, "open preloadstatic filename", val);
2552 return 1;
2553 }
2554
2555 StaticPreloadInfo *nfo = new StaticPreloadInfo;
2556 // Max 64Kb ok?
2557 nfo->data = (char *)malloc(65536);
2558 nfo->len = read(fp, (void *)nfo->data, 65536);
2559 close(fp);
2560
2561 if (nfo->len <= 0) {
2562 eDest.Emsg("Config", errno, "read from preloadstatic filename", val);
2563 return 1;
2564 }
2565
2566 if (nfo->len >= 65536) {
2567 eDest.Emsg("Config", "Truncated preloadstatic filename. Max is 64 KB '", val, "'");
2568 return 1;
2569 }
2570
2571 // Record the value
2572 //
2573 if (!staticpreload)
2575
2576 staticpreload->Rep((const char *)key, nfo);
2577 return 0;
2578}
2579
2580/******************************************************************************/
2581/* x s t a t i c h e a d e r */
2582/******************************************************************************/
2583
2584//
2585// xstaticheader parses the http.staticheader director with the following syntax:
2586//
2587// http.staticheader [-verb=[GET|HEAD|...]]* header [value]
2588//
2589// When set, this will cause XrdHttp to always return the specified header and
2590// value.
2591//
2592// Setting this option multiple times is additive (multiple headers may be set).
2593// Omitting the value will cause the static header setting to be unset.
2594//
2595// Omitting the -verb argument will cause it the header to be set unconditionally
2596// for all requests.
2597int XrdHttpProtocol::xstaticheader(XrdOucStream & Config) {
2598 auto val = Config.GetWord();
2599 std::vector<std::string> verbs;
2600 while (true) {
2601 if (!val || !val[0]) {
2602 eDest.Emsg("Config", "http.staticheader requires the header to be specified");
2603 return 1;
2604 }
2605
2606 std::string match_verb;
2607 std::string_view val_str(val);
2608 if (val_str.substr(0, 6) == "-verb=") {
2609 verbs.emplace_back(val_str.substr(6));
2610 } else if (val_str == "-") {
2611 eDest.Emsg("Config", "http.staticheader is ignoring unknown flag: ", val_str.data());
2612 } else {
2613 break;
2614 }
2615
2616 val = Config.GetWord();
2617 }
2618 if (verbs.empty()) {
2619 verbs.emplace_back();
2620 }
2621
2622 std::string header = val;
2623
2624 val = Config.GetWord();
2625 std::string header_value;
2626 if (val && val[0]) {
2627 header_value = val;
2628 }
2629
2630 for (const auto &verb : verbs) {
2631 auto iter = m_staticheader_map.find(verb);
2632 if (iter == m_staticheader_map.end() && !header_value.empty()) {
2633 m_staticheader_map.insert(iter, {verb, {{header, header_value}}});
2634 } else if (header_value.empty()) {
2635 iter->second.clear();
2636 } else {
2637 iter->second.emplace_back(header, header_value);
2638 }
2639 }
2640
2641 return 0;
2642}
2643
2644
2645/******************************************************************************/
2646/* x s e l f h t t p s 2 h t t p */
2647/******************************************************************************/
2648
2649/* Function: selfhttps2http
2650
2651 Purpose: To parse the directive: selfhttps2http <yes|no|0|1>
2652
2653 <val> this server will redirect HTTPS to itself using HTTP+token
2654
2655 Output: 0 upon success or !0 upon failure.
2656 */
2657
2658int XrdHttpProtocol::xselfhttps2http(XrdOucStream & Config) {
2659 char *val;
2660
2661 // Get the path
2662 //
2663 val = Config.GetWord();
2664 if (!val || !val[0]) {
2665 eDest.Emsg("Config", "selfhttps2http flag not specified");
2666 return 1;
2667 }
2668
2669 // Record the value
2670 //
2671 selfhttps2http = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2672
2673
2674 return 0;
2675}
2676
2677/******************************************************************************/
2678/* x s e c x t r a c t o r */
2679/******************************************************************************/
2680
2681/* Function: xsecxtractor
2682
2683 Purpose: To parse the directive: secxtractor [required] <path> <params>
2684
2685 required optional parameter which if present treats any secxtractor
2686 errors as fatal.
2687 <path> the path of the plugin to be loaded
2688 <params> parameters passed to the secxtractor library
2689
2690 Output: 0 upon success or !0 upon failure.
2691 */
2692
2693int XrdHttpProtocol::xsecxtractor(XrdOucStream& Config) {
2694 char *val;
2695
2696 // Get the path
2697 //
2698 val = Config.GetWord();
2699 if (!val || !val[0]) {
2700 eDest.Emsg("Config", "No security extractor plugin specified.");
2701 return 1;
2702 } else {
2703 // Handle optional parameter [required]
2704 //
2705 if (!strncmp(val, "required", 8)) {
2706 isRequiredXtractor = true;
2707 val = Config.GetWord();
2708
2709 if (!val || !val[0]) {
2710 eDest.Emsg("Config", "No security extractor plugin after [required] "
2711 "parameter");
2712 return 1;
2713 }
2714 }
2715
2716 char libName[4096];
2717 strlcpy(libName, val, sizeof(libName));
2718 libName[sizeof(libName) - 1] = '\0';
2719 char libParms[4096];
2720
2721 if (!Config.GetRest(libParms, 4095)) {
2722 eDest.Emsg("Config", "secxtractor config params longer than 4k");
2723 return 1;
2724 }
2725
2726 // Try to load the plugin (if available) that extracts info from the
2727 // user cert/proxy
2728 if (LoadSecXtractor(&eDest, libName, libParms)) {
2729 return 1;
2730 }
2731 }
2732
2733 return 0;
2734}
2735
2736/******************************************************************************/
2737/* x e x t h a n d l e r */
2738/******************************************************************************/
2739
2740/* Function: xexthandler
2741 *
2742 * Purpose: To parse the directive: exthandler <name> <path> <initparm>
2743 *
2744 * <name> a unique name (max 16chars) to be given to this
2745 * instance, e.g 'myhandler1'
2746 * <path> the path of the plugin to be loaded
2747 * <initparm> a string parameter (e.g. a config file) that is
2748 * passed to the initialization of the plugin
2749 *
2750 * Output: 0 upon success or !0 upon failure.
2751 */
2752
2753int XrdHttpProtocol::xexthandler(XrdOucStream &Config,
2754 std::vector<extHInfo> &hiVec) {
2755 char *val, path[1024], namebuf[1024];
2756 char *parm;
2757 // By default, every external handler need TLS configured to be loaded
2758 bool noTlsOK = false;
2759
2760 // Get the name
2761 //
2762 val = Config.GetWord();
2763 if (!val || !val[0]) {
2764 eDest.Emsg("Config", "No instance name specified for an http external handler plugin.");
2765 return 1;
2766 }
2767 if (strlen(val) >= 16) {
2768 eDest.Emsg("Config", "Instance name too long for an http external handler plugin.");
2769 return 1;
2770 }
2771 strncpy(namebuf, val, sizeof(namebuf));
2772 namebuf[ sizeof(namebuf)-1 ] = '\0';
2773
2774 // Get the +notls option if it was provided
2775 val = Config.GetWord();
2776
2777 if(val && !strcmp("+notls",val)) {
2778 noTlsOK = true;
2779 val = Config.GetWord();
2780 }
2781
2782 // Get the path
2783 //
2784 if (!val || !val[0]) {
2785 eDest.Emsg("Config", "No http external handler plugin specified.");
2786 return 1;
2787 }
2788 if (strlen(val) >= (int)sizeof(path)) {
2789 eDest.Emsg("Config", "Path too long for an http external handler plugin.");
2790 return 1;
2791 }
2792
2793 strcpy(path, val);
2794
2795 // Everything else is a free string
2796 //
2797 parm = Config.GetWord();
2798
2799 // Verify whether this is a duplicate (we never supported replacements)
2800 //
2801 for (int i = 0; i < (int)hiVec.size(); i++)
2802 {if (hiVec[i].extHName == namebuf) {
2803 eDest.Emsg("Config", "Instance name already present for "
2804 "http external handler plugin",
2805 hiVec[i].extHPath.c_str());
2806 return 1;
2807 }
2808 }
2809
2810 // Verify that we don't have more already than we are allowed to have
2811 //
2812 if (hiVec.size() >= MAX_XRDHTTPEXTHANDLERS) {
2813 eDest.Emsg("Config", "Cannot load one more exthandler. Max is 4");
2814 return 1;
2815 }
2816
2817 // Create an info struct and push it on the list of ext handlers to load
2818 //
2819 hiVec.push_back(extHInfo(namebuf, path, (parm ? parm : ""), noTlsOK));
2820
2821 return 0;
2822}
2823
2824/******************************************************************************/
2825/* x h e a d e r 2 c g i */
2826/******************************************************************************/
2827
2828/* Function: xheader2cgi
2829 *
2830 * Purpose: To parse the directive: header2cgi <headerkey> <cgikey>
2831 *
2832 * <headerkey> the name of an incoming HTTP header
2833 * to be transformed
2834 * <cgikey> the name to be given when adding it to the cgi info
2835 * that is kept only internally
2836 *
2837 * Output: 0 upon success or !0 upon failure.
2838 */
2839
2840int XrdHttpProtocol::xheader2cgi(XrdOucStream & Config) {
2841 return parseHeader2CGI(Config,eDest,hdr2cgimap);
2842}
2843
2844/******************************************************************************/
2845/* x s s l c a d i r */
2846/******************************************************************************/
2847
2848/* Function: xsslcadir
2849
2850 Purpose: To parse the directive: sslcadir <path>
2851
2852 <path> the path of the server key to be used.
2853
2854 Output: 0 upon success or !0 upon failure.
2855 */
2856
2857int XrdHttpProtocol::xsslcadir(XrdOucStream & Config) {
2858 char *val;
2859
2860 // Get the path
2861 //
2862 val = Config.GetWord();
2863 if (!val || !val[0]) {
2864 eDest.Emsg("Config", "HTTP X509 CAdir not specified");
2865 return 1;
2866 }
2867
2868 // Record the path
2869 //
2870 if (sslcadir) free(sslcadir);
2871 sslcadir = strdup(val);
2872
2873 if (xrdctxVer){ HTTPS_ALERT("cadir","tlsca",false); }
2874 return 0;
2875}
2876
2877/******************************************************************************/
2878/* x s s l c i p h e r f i l t e r */
2879/******************************************************************************/
2880
2881/* Function: xsslcipherfilter
2882
2883 Purpose: To parse the directive: cipherfilter <filter>
2884
2885 <filter> the filter string to be used when generating
2886 the SSL cipher list
2887
2888 Output: 0 upon success or !0 upon failure.
2889 */
2890
2891int XrdHttpProtocol::xsslcipherfilter(XrdOucStream & Config) {
2892 char *val;
2893
2894 // Get the filter string
2895 //
2896 val = Config.GetWord();
2897 if (!val || !val[0]) {
2898 eDest.Emsg("Config", "SSL cipherlist filter string not specified");
2899 return 1;
2900 }
2901
2902 // Record the filter string
2903 //
2905 sslcipherfilter = strdup(val);
2906
2907 return 0;
2908}
2909
2910/******************************************************************************/
2911/* x t l s r e u s e */
2912/******************************************************************************/
2913
2914/* Function: xtlsreuse
2915
2916 Purpose: To parse the directive: tlsreuse {on | off}
2917
2918 Output: 0 upon success or 1 upon failure.
2919 */
2920
2921int XrdHttpProtocol::xtlsreuse(XrdOucStream & Config) {
2922
2923 char *val;
2924
2925// Get the argument
2926//
2927 val = Config.GetWord();
2928 if (!val || !val[0])
2929 {eDest.Emsg("Config", "tlsreuse argument not specified"); return 1;}
2930
2931// If it's off, we set it off
2932//
2933 if (!strcmp(val, "off"))
2935 return 0;
2936 }
2937
2938// If it's on we set it on.
2939//
2940 if (!strcmp(val, "on"))
2942 return 0;
2943 }
2944
2945// Bad argument
2946//
2947 eDest.Emsg("config", "invalid tlsreuse parameter -", val);
2948 return 1;
2949}
2950
2951int XrdHttpProtocol::xauth(XrdOucStream &Config) {
2952 char *val = Config.GetWord();
2953 if(val) {
2954 if(!strcmp("tpc",val)) {
2955 if(!(val = Config.GetWord())) {
2956 eDest.Emsg("Config", "http.auth tpc value not specified."); return 1;
2957 } else {
2958 if(!strcmp("fcreds",val)) {
2959 tpcForwardCreds = true;
2960 } else {
2961 eDest.Emsg("Config", "http.auth tpc value is invalid"); return 1;
2962 }
2963 }
2964 } else {
2965 eDest.Emsg("Config", "http.auth value is invalid"); return 1;
2966 }
2967 }
2968 return 0;
2969}
2970
2971/******************************************************************************/
2972/* x t r a c e */
2973/******************************************************************************/
2974
2975/* Function: xtrace
2976
2977 Purpose: To parse the directive: trace <events>
2978
2979 <events> the blank separated list of events to trace. Trace
2980 directives are cumulative.
2981
2982 Output: 0 upon success or 1 upon failure.
2983 */
2984
2985int XrdHttpProtocol::xtrace(XrdOucStream & Config) {
2986
2987 char *val;
2988
2989 static struct traceopts {
2990 const char *opname;
2991 int opval;
2992 } tropts[] = {
2993 {"all", TRACE_ALL},
2994 {"auth", TRACE_AUTH},
2995 {"debug", TRACE_DEBUG},
2996 {"mem", TRACE_MEM},
2997 {"redirect", TRACE_REDIR},
2998 {"request", TRACE_REQ},
2999 {"response", TRACE_RSP}
3000 };
3001 int i, neg, trval = 0, numopts = sizeof (tropts) / sizeof (struct traceopts);
3002
3003 if (!(val = Config.GetWord())) {
3004 eDest.Emsg("config", "trace option not specified");
3005 return 1;
3006 }
3007 while (val) {
3008 if (!strcmp(val, "off")) trval = 0;
3009 else {
3010 if ((neg = (val[0] == '-' && val[1]))) val++;
3011 for (i = 0; i < numopts; i++) {
3012 if (!strcmp(val, tropts[i].opname)) {
3013 if (neg) trval &= ~tropts[i].opval;
3014 else trval |= tropts[i].opval;
3015 break;
3016 }
3017 }
3018 if (i >= numopts)
3019 eDest.Emsg("config", "invalid trace option", val);
3020 }
3021 val = Config.GetWord();
3022 }
3023 XrdHttpTrace.What = trval;
3024 return 0;
3025}
3026
3027int XrdHttpProtocol::doStat(char *fname) {
3028 int l;
3029 bool b;
3030 CurrentReq.filesize = 0;
3033
3034 memset(&CurrentReq.xrdreq, 0, sizeof (ClientRequest));
3036 memset(CurrentReq.xrdreq.stat.reserved, 0,
3037 sizeof (CurrentReq.xrdreq.stat.reserved));
3038 l = strlen(fname) + 1;
3039 CurrentReq.xrdreq.stat.dlen = htonl(l);
3040
3041 if (!Bridge) return -1;
3042 b = Bridge->Run((char *) &CurrentReq.xrdreq, fname, l);
3043 if (!b) {
3044 return -1;
3045 }
3046
3047
3048 return 0;
3049}
3050
3051/******************************************************************************/
3052/* d o C h k s u m */
3053/******************************************************************************/
3054
3055int XrdHttpProtocol::doChksum(const XrdOucString &fname) {
3056 size_t length;
3057 memset(&CurrentReq.xrdreq, 0, sizeof (ClientRequest));
3063 length = fname.length() + 1;
3064 CurrentReq.xrdreq.query.dlen = htonl(length);
3065
3066 if (!Bridge) return -1;
3067
3068 return Bridge->Run(reinterpret_cast<char *>(&CurrentReq.xrdreq), const_cast<char *>(fname.c_str()), length) ? 0 : -1;
3069}
3070
3071
3072static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION);
3073
3074// Loads the SecXtractor plugin, if available
3075int XrdHttpProtocol::LoadSecXtractor(XrdSysError *myeDest, const char *libName,
3076 const char *libParms) {
3077
3078
3079 // We don't want to load it more than once
3080 if (secxtractor) return 1;
3081
3082 XrdOucPinLoader myLib(myeDest, &compiledVer, "secxtractorlib", libName);
3084
3085 // Get the entry point of the object creator
3086 //
3087 ep = (XrdHttpSecXtractor *(*)(XrdHttpSecXtractorArgs))(myLib.Resolve("XrdHttpGetSecXtractor"));
3088 if (ep && (secxtractor = ep(myeDest, NULL, libParms))) return 0;
3089 myLib.Unload();
3090 return 1;
3091}
3092/******************************************************************************/
3093/* L o a d E x t H a n d l e r */
3094/******************************************************************************/
3095
3096int XrdHttpProtocol::LoadExtHandlerNoTls(std::vector<extHInfo> &hiVec, const char *cFN, XrdOucEnv &myEnv) {
3097 for (int i = 0; i < (int) hiVec.size(); i++) {
3098 if(hiVec[i].extHNoTlsOK) {
3099 // The external plugin does not need TLS to be loaded
3100 if (LoadExtHandler(&eDest, hiVec[i].extHPath.c_str(), cFN,
3101 hiVec[i].extHParm.c_str(), &myEnv,
3102 hiVec[i].extHName.c_str()))
3103 return 1;
3104 }
3105 }
3106 return 0;
3107}
3108
3109int XrdHttpProtocol::LoadExtHandler(std::vector<extHInfo> &hiVec,
3110 const char *cFN, XrdOucEnv &myEnv) {
3111
3112 // Add the pointer to the cadir and the cakey to the environment.
3113 //
3114 if (sslcadir) myEnv.Put("http.cadir", sslcadir);
3115 if (sslcafile) myEnv.Put("http.cafile", sslcafile);
3116 if (sslcert) myEnv.Put("http.cert", sslcert);
3117 if (sslkey) myEnv.Put("http.key" , sslkey);
3118
3119 // Load all of the specified external handlers.
3120 //
3121 for (int i = 0; i < (int)hiVec.size(); i++) {
3122 // Only load the external handlers that were not already loaded
3123 // by LoadExtHandlerNoTls(...)
3124 if(!ExtHandlerLoaded(hiVec[i].extHName.c_str())) {
3125 if (LoadExtHandler(&eDest, hiVec[i].extHPath.c_str(), cFN,
3126 hiVec[i].extHParm.c_str(), &myEnv,
3127 hiVec[i].extHName.c_str())) return 1;
3128 }
3129 }
3130 return 0;
3131}
3132
3133// Loads the external handler plugin, if available
3134int XrdHttpProtocol::LoadExtHandler(XrdSysError *myeDest, const char *libName,
3135 const char *configFN, const char *libParms,
3136 XrdOucEnv *myEnv, const char *instName) {
3137
3138
3139 // This function will avoid loading doubles. No idea why this happens
3140 if (ExtHandlerLoaded(instName)) {
3141 eDest.Emsg("Config", "Instance name already present for an http external handler plugin.");
3142 return 1;
3143 }
3144 if (exthandlercnt >= MAX_XRDHTTPEXTHANDLERS) {
3145 eDest.Emsg("Config", "Cannot load one more exthandler. Max is 4");
3146 return 1;
3147 }
3148
3149 XrdOucPinLoader myLib(myeDest, &compiledVer, "exthandlerlib", libName);
3151
3152 // Get the entry point of the object creator
3153 //
3154 ep = (XrdHttpExtHandler *(*)(XrdHttpExtHandlerArgs))(myLib.Resolve("XrdHttpGetExtHandler"));
3155
3156 XrdHttpExtHandler *newhandler;
3157 if (ep && (newhandler = ep(myeDest, configFN, libParms, myEnv))) {
3158
3159 // Handler has been loaded, it's the last one in the list
3160 strncpy( exthandler[exthandlercnt].name, instName, 16 );
3161 exthandler[exthandlercnt].name[15] = '\0';
3162 exthandler[exthandlercnt++].ptr = newhandler;
3163
3164 return 0;
3165 }
3166
3167 myLib.Unload();
3168 return 1;
3169}
3170
3171
3172
3173// Tells if we have already loaded a certain exthandler. Try to
3174// privilege speed, as this func may be invoked pretty often
3175bool XrdHttpProtocol::ExtHandlerLoaded(const char *handlername) {
3176 for (int i = 0; i < exthandlercnt; i++) {
3177 if ( !strncmp(exthandler[i].name, handlername, 15) ) {
3178 return true;
3179 }
3180 }
3181 return false;
3182}
3183
3184// Locates a matching external handler for a given request, if available. Try to
3185// privilege speed, as this func is invoked for every incoming request
3186XrdHttpExtHandler * XrdHttpProtocol::FindMatchingExtHandler(const XrdHttpReq &req) {
3187
3188 for (int i = 0; i < exthandlercnt; i++) {
3189 if (exthandler[i].ptr->MatchesPath(req.requestverb.c_str(), req.resource.c_str())) {
3190 return exthandler[i].ptr;
3191 }
3192 }
3193 return NULL;
3194}
#define kXR_isManager
kXR_unt16 requestid
Definition XProtocol.hh:630
kXR_char reserved1[2]
Definition XProtocol.hh:632
kXR_char reserved[11]
Definition XProtocol.hh:770
kXR_char reserved2[8]
Definition XProtocol.hh:634
kXR_char fhandle[4]
Definition XProtocol.hh:633
@ kXR_query
Definition XProtocol.hh:113
@ kXR_stat
Definition XProtocol.hh:129
#define kXR_isServer
struct ClientQueryRequest query
Definition XProtocol.hh:866
kXR_unt16 requestid
Definition XProtocol.hh:768
struct ClientStatRequest stat
Definition XProtocol.hh:873
@ kXR_Qcksum
Definition XProtocol.hh:617
#define DEBUG(x)
#define XrdHttpExtHandlerArgs
static int BIO_XrdLink_create(BIO *bio)
const char * XrdHttpSecEntityTident
int BIO_XrdLink_write(BIO *bio, const char *data, size_t datal, size_t *written)
#define HTTPS_ALERT(x, y, z)
static long BIO_XrdLink_ctrl(BIO *bio, int cmd, long num, void *ptr)
#define TS_Xeq(x, m)
XrdSysTrace XrdHttpTrace("http")
static int BIO_XrdLink_read(BIO *bio, char *data, size_t datal, size_t *read)
#define TS_Xeq3(x, m)
static int BIO_XrdLink_destroy(BIO *bio)
static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION)
#define MAX_XRDHTTPEXTHANDLERS
#define XrdHttpSecXtractorArgs
#define TRACE_AUTH
#define TRACE_REQ
#define TRACE_RSP
#define TRACE_REDIR
int fclose(FILE *stream)
#define close(a)
Definition XrdPosix.hh:48
#define fstat(a, b)
Definition XrdPosix.hh:62
#define open
Definition XrdPosix.hh:76
#define stat(a, b)
Definition XrdPosix.hh:101
#define read(a, b, c)
Definition XrdPosix.hh:82
#define eMsg(x)
struct myOpts opts
size_t strlcpy(char *dst, const char *src, size_t sz)
#define TLS_SET_VDEPTH(cOpts, vdv)
#define TLS_SET_REFINT(cOpts, refi)
#define TRACE_DEBUG
Definition XrdTrace.hh:36
#define TRACE_MEM
Definition XrdTrace.hh:38
#define TRACE(act, x)
Definition XrdTrace.hh:63
#define TRACE_ALL
Definition XrdTrace.hh:35
#define TRACEI(act, x)
Definition XrdTrace.hh:66
void Release(XrdBuffer *bp)
Definition XrdBuffer.cc:221
char * buff
Definition XrdBuffer.hh:45
static char * secretkey
The key used to calculate the url hashes.
static char * gridmap
Gridmap file location. The same used by XrdSecGsi.
static XrdScheduler * Sched
static kXR_int32 myRole
Our role.
static char * sslcafile
static char * Port_str
Our port, as a string.
XrdXrootd::Bridge * Bridge
The Bridge that we use to exercise the xrootd internals.
static char * staticredir
static XrdSysError eDest
static bool selfhttps2http
If client is HTTPS, self-redirect with HTTP+token.
int doChksum(const XrdOucString &fname)
Perform a checksum request.
static XrdOucHash< StaticPreloadInfo > * staticpreload
static char * xrd_cslist
The list of checksums that were configured via the xrd.cksum parameter on the server config file.
static char * sslcipherfilter
static std::map< std::string, std::string > hdr2cgimap
Rules that turn HTTP headers to cgi tokens in the URL, for internal comsumption.
static char * sslcert
OpenSSL stuff.
XrdLink * Link
The link we are bound to.
static char * sslkey
int doStat(char *fname)
Perform a Stat request.
static int readWait
Timeout for reading data.
static std::unordered_map< std::string, std::vector< std::pair< std::string, std::string > > > m_staticheader_map
The static headers to always return; map is from verb to a list of (header, val) pairs.
static char * sslcadir
static bool compatNameGeneration
static bool isdesthttps
True if the redirections must be towards https targets.
static XrdObjectQ< XrdHttpProtocol > ProtStack
static bool isRequiredGridmap
static char * listredir
Url to redirect to in the case a listing is requested.
static int crlRefIntervalSec
CRL thread refresh interval.
static int Port
Our port.
static XrdBuffManager * BPool
static std::unordered_map< std::string, std::string > m_staticheaders
static bool tpcForwardCreds
If set to true, the HTTP TPC transfers will forward the credentials to redirected hosts.
static bool listdeny
If true, any form of listing is denied.
static int parseHeader2CGI(XrdOucStream &Config, XrdSysError &err, std::map< std::string, std::string > &header2cgi)
Use this function to parse header2cgi configurations.
XrdSecEntity SecEntity
Authentication area.
static bool embeddedstatic
If true, use the embedded css and icons.
static int sslverifydepth
Depth of verification of a certificate chain.
static int Configure(char *parms, XrdProtocol_Config *pi)
Read and apply the configuration.
static int Configure(XrdSysError &Eroute, const char *const parms, Configuration &cfg)
int reqstate
State machine to talk to the bridge.
XrdOucString resource
The resource specified by the request, stripped of opaque data.
std::string requestverb
long filemodtime
long long filesize
ClientRequest xrdreq
The last issued xrd request, often pending.
virtual void reset()
virtual int FreeSSL(SSL *)
void Set(int inQMax, time_t agemax=1800)
Definition XrdObject.icc:90
static bool Import(const char *var, char *&val)
Definition XrdOucEnv.cc:204
void Put(const char *varname, const char *value)
Definition XrdOucEnv.hh:85
T * Rep(const char *KeyVal, T *KeyData, const int LifeTime=0, XrdOucHash_Options opt=Hash_default)
void insert(const int i, int start=-1)
void assign(const char *s, int j, int k=-1)
int length() const
const char * c_str() const
XrdBuffManager * BPool
XrdScheduler * Sched
XrdTlsContext * tlsCtx
XrdSysError * eDest
XrdOucEnv * theEnv
char * vorg
Entity's virtual organization(s)
const char * tident
Trace identifier always preset.
char * caps
Entity's capabilities.
char * grps
Entity's group name(s)
void Reset(const char *spV=0)
char * name
Entity's name.
char * role
Entity's role(s)
char * endorsements
Protocol specific endorsements.
char * moninfo
Information for monitoring.
char * host
Entity's host name dnr dependent.
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
XrdSysLogger * logger(XrdSysLogger *lp=0)
void SetLogger(XrdSysLogger *logp)
int SessionCache(int opts=scNone, const char *id=0, int idlen=0)
static const int DEFAULT_CRL_REF_INT_SEC
Default CRL refresh interval in seconds.
static const uint64_t servr
This is a server context.
static const uint64_t rfCRL
Turn on the CRL refresh thread.
static const uint64_t logVF
Log verify failures.
static const uint64_t artON
Auto retry Handshake.
const CTX_Params * GetParams()
static const int scOff
Turn off cache.
bool SetContextCiphers(const char *ciphers)
static const int scSrvr
Turn on cache server mode (default)
virtual bool Run(const char *xreqP, char *xdataP=0, int xdataL=0)=0
XrdCmsConfig Config
static const int hsmOff
static const int hsmMan
static const int hsmOn
std::string cafile
-> ca cert file.
std::string cadir
-> ca cert directory.
int crlRT
crl refresh interval time in seconds
std::string pkey
-> private key path.
std::string cert
-> certificate path.

◆ TRACELINK [1/3]

#define TRACELINK   lp

Definition at line 220 of file XrdHttpProtocol.cc.

◆ TRACELINK [2/3]

#define TRACELINK   Link

Definition at line 220 of file XrdHttpProtocol.cc.

◆ TRACELINK [3/3]

#define TRACELINK   Link

Definition at line 220 of file XrdHttpProtocol.cc.

◆ TS_Xeq

#define TS_Xeq (   x,
 
)    (!strcmp(x,var)) GoNo = m(Config)

Definition at line 976 of file XrdHttpProtocol.cc.

◆ TS_Xeq3

#define TS_Xeq3 (   x,
 
)    (!strcmp(x,var)) GoNo = m(Config, extHIVec)

Definition at line 978 of file XrdHttpProtocol.cc.

◆ XRHTTP_TK_GRACETIME

#define XRHTTP_TK_GRACETIME   600

Definition at line 58 of file XrdHttpProtocol.cc.

Function Documentation

◆ BIO_get_data()

void * BIO_get_data ( BIO *  bio)

Definition at line 161 of file XrdHttpProtocol.cc.

161 {
162 return bio->ptr;
163}

Referenced by BIO_XrdLink_destroy(), BIO_XrdLink_read(), and BIO_XrdLink_write().

+ Here is the caller graph for this function:

◆ BIO_get_flags()

int BIO_get_flags ( BIO *  bio)

Definition at line 168 of file XrdHttpProtocol.cc.

168 {
169 return bio->flags;
170}

◆ BIO_get_init()

int BIO_get_init ( BIO *  bio)

Definition at line 175 of file XrdHttpProtocol.cc.

175 {
176 return bio->init;
177}

◆ BIO_get_shutdown()

int BIO_get_shutdown ( BIO *  bio)

Definition at line 184 of file XrdHttpProtocol.cc.

184 {
185 return bio->shutdown;
186}

Referenced by BIO_XrdLink_ctrl(), and BIO_XrdLink_destroy().

+ Here is the caller graph for this function:

◆ BIO_set_data()

void BIO_set_data ( BIO *  bio,
void *  ptr 
)

Definition at line 164 of file XrdHttpProtocol.cc.

164 {
165 bio->ptr = ptr;
166}

Referenced by BIO_XrdLink_create().

+ Here is the caller graph for this function:

◆ BIO_set_flags()

void BIO_set_flags ( BIO *  bio,
int  flags 
)

Definition at line 172 of file XrdHttpProtocol.cc.

172 {
173 bio->flags = flags;
174}

Referenced by BIO_XrdLink_create(), BIO_XrdLink_destroy(), and Tobase64().

+ Here is the caller graph for this function:

◆ BIO_set_init()

void BIO_set_init ( BIO *  bio,
int  init 
)

Definition at line 178 of file XrdHttpProtocol.cc.

178 {
179 bio->init = init;
180}

Referenced by BIO_XrdLink_create(), and BIO_XrdLink_destroy().

+ Here is the caller graph for this function:

◆ BIO_set_shutdown()

void BIO_set_shutdown ( BIO *  bio,
int  shut 
)

Definition at line 181 of file XrdHttpProtocol.cc.

181 {
182 bio->shutdown = shut;
183}

Referenced by BIO_XrdLink_ctrl().

+ Here is the caller graph for this function:

◆ BIO_XrdLink_create()

static int BIO_XrdLink_create ( BIO *  bio)
static

Definition at line 408 of file XrdHttpProtocol.cc.

409{
410
411
412 BIO_set_init(bio, 0);
413 //BIO_set_next(bio, 0);
414 BIO_set_data(bio, NULL);
415 BIO_set_flags(bio, 0);
416
417#if OPENSSL_VERSION_NUMBER < 0x10100000L
418
419 bio->num = 0;
420
421#endif
422
423 return 1;
424}
void BIO_set_init(BIO *bio, int init)
void BIO_set_data(BIO *bio, void *ptr)
void BIO_set_flags(BIO *bio, int flags)

References BIO_set_data(), BIO_set_flags(), and BIO_set_init().

+ Here is the call graph for this function:

◆ BIO_XrdLink_ctrl()

static long BIO_XrdLink_ctrl ( BIO *  bio,
int  cmd,
long  num,
void *  ptr 
)
static

Definition at line 441 of file XrdHttpProtocol.cc.

442{
443 long ret = 1;
444 switch (cmd) {
445 case BIO_CTRL_GET_CLOSE:
446 ret = BIO_get_shutdown(bio);
447 break;
448 case BIO_CTRL_SET_CLOSE:
449 BIO_set_shutdown(bio, (int)num);
450 break;
451 case BIO_CTRL_DUP:
452 case BIO_CTRL_FLUSH:
453 ret = 1;
454 break;
455 default:
456 ret = 0;
457 break;
458 }
459 return ret;
460}
int BIO_get_shutdown(BIO *bio)
void BIO_set_shutdown(BIO *bio, int shut)

References BIO_get_shutdown(), and BIO_set_shutdown().

+ Here is the call graph for this function:

◆ BIO_XrdLink_destroy()

static int BIO_XrdLink_destroy ( BIO *  bio)
static

Definition at line 427 of file XrdHttpProtocol.cc.

428{
429 if (bio == NULL) return 0;
430 if (BIO_get_shutdown(bio)) {
431 if (BIO_get_data(bio)) {
432 static_cast<XrdLink*>(BIO_get_data(bio))->Close();
433 }
434 BIO_set_init(bio, 0);
435 BIO_set_flags(bio, 0);
436 }
437 return 1;
438}
void * BIO_get_data(BIO *bio)
CloseImpl< false > Close(Ctx< File > file, uint16_t timeout=0)
Factory for creating CloseImpl objects.

References BIO_get_data(), BIO_get_shutdown(), BIO_set_flags(), and BIO_set_init().

+ Here is the call graph for this function:

◆ BIO_XrdLink_read()

static int BIO_XrdLink_read ( BIO *  bio,
char *  data,
size_t  datal,
size_t *  read 
)
static

Definition at line 367 of file XrdHttpProtocol.cc.

368{
369 if (!data || !bio) {
370 *read = 0;
371 return 0;
372 }
373
374 errno = 0;
375
376 XrdLink *lp = static_cast<XrdLink *>(BIO_get_data(bio));
377 int ret = lp->Recv(data, datal);
378 BIO_clear_retry_flags(bio);
379 if (ret <= 0) {
380 *read = 0;
381 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
382 BIO_set_retry_read(bio);
383 return ret;
384 }
385 *read = ret;
386}

References BIO_get_data(), read, and XrdLink::Recv().

+ Here is the call graph for this function:

◆ BIO_XrdLink_write()

int BIO_XrdLink_write ( BIO *  bio,
const char *  data,
size_t  datal,
size_t *  written 
)

Definition at line 324 of file XrdHttpProtocol.cc.

325{
326 if (!data || !bio) {
327 *written = 0;
328 return 0;
329 }
330
331 XrdLink *lp=static_cast<XrdLink *>(BIO_get_data(bio));
332
333 errno = 0;
334 int ret = lp->Send(data, datal);
335 BIO_clear_retry_flags(bio);
336 if (ret <= 0) {
337 *written = 0;
338 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
339 BIO_set_retry_write(bio);
340 return ret;
341 }
342 *written = ret;
343 return 1;
344}

References BIO_get_data(), and XrdLink::Send().

+ Here is the call graph for this function:

◆ XrdVERSIONINFODEF()

static XrdVERSIONINFODEF ( compiledVer  ,
XrdHttpProtocolTest  ,
XrdVNUMBER  ,
XrdVERSION   
)
static

Variable Documentation

◆ XrdHttpSecEntityTident

const char* XrdHttpSecEntityTident = "http"

Definition at line 66 of file XrdHttpProtocol.cc.

◆ XrdHttpTrace

XrdSysTrace XrdHttpTrace("http") ( "http"  )