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/XrdOuca2x.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 "XrdHttpCors/XrdHttpCors.hh"
#include <charconv>
#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
 
bool XrdHttpProtoInfo::tlsClientAuth = true
 
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 988 of file XrdHttpProtocol.cc.

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

◆ TRACELINK [2/3]

#define TRACELINK   Link

Definition at line 227 of file XrdHttpProtocol.cc.

◆ TRACELINK [3/3]

#define TRACELINK   Link

Definition at line 227 of file XrdHttpProtocol.cc.

◆ TS_Xeq

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

Definition at line 984 of file XrdHttpProtocol.cc.

◆ TS_Xeq3

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

Definition at line 986 of file XrdHttpProtocol.cc.

◆ XRHTTP_TK_GRACETIME

#define XRHTTP_TK_GRACETIME   600

Definition at line 61 of file XrdHttpProtocol.cc.

Function Documentation

◆ BIO_get_data()

void * BIO_get_data ( BIO *  bio)

Definition at line 168 of file XrdHttpProtocol.cc.

168 {
169 return bio->ptr;
170}

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 175 of file XrdHttpProtocol.cc.

175 {
176 return bio->flags;
177}

◆ BIO_get_init()

int BIO_get_init ( BIO *  bio)

Definition at line 182 of file XrdHttpProtocol.cc.

182 {
183 return bio->init;
184}

◆ BIO_get_shutdown()

int BIO_get_shutdown ( BIO *  bio)

Definition at line 191 of file XrdHttpProtocol.cc.

191 {
192 return bio->shutdown;
193}

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 171 of file XrdHttpProtocol.cc.

171 {
172 bio->ptr = ptr;
173}

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 179 of file XrdHttpProtocol.cc.

179 {
180 bio->flags = flags;
181}

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 185 of file XrdHttpProtocol.cc.

185 {
186 bio->init = init;
187}

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 188 of file XrdHttpProtocol.cc.

188 {
189 bio->shutdown = shut;
190}

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 415 of file XrdHttpProtocol.cc.

416{
417
418
419 BIO_set_init(bio, 0);
420 //BIO_set_next(bio, 0);
421 BIO_set_data(bio, NULL);
422 BIO_set_flags(bio, 0);
423
424#if OPENSSL_VERSION_NUMBER < 0x10100000L
425
426 bio->num = 0;
427
428#endif
429
430 return 1;
431}
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 448 of file XrdHttpProtocol.cc.

449{
450 long ret = 1;
451 switch (cmd) {
452 case BIO_CTRL_GET_CLOSE:
453 ret = BIO_get_shutdown(bio);
454 break;
455 case BIO_CTRL_SET_CLOSE:
456 BIO_set_shutdown(bio, (int)num);
457 break;
458 case BIO_CTRL_DUP:
459 case BIO_CTRL_FLUSH:
460 ret = 1;
461 break;
462 default:
463 ret = 0;
464 break;
465 }
466 return ret;
467}
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 434 of file XrdHttpProtocol.cc.

435{
436 if (bio == NULL) return 0;
437 if (BIO_get_shutdown(bio)) {
438 if (BIO_get_data(bio)) {
439 static_cast<XrdLink*>(BIO_get_data(bio))->Close();
440 }
441 BIO_set_init(bio, 0);
442 BIO_set_flags(bio, 0);
443 }
444 return 1;
445}
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 374 of file XrdHttpProtocol.cc.

375{
376 if (!data || !bio) {
377 *read = 0;
378 return 0;
379 }
380
381 errno = 0;
382
383 XrdLink *lp = static_cast<XrdLink *>(BIO_get_data(bio));
384 int ret = lp->Recv(data, datal);
385 BIO_clear_retry_flags(bio);
386 if (ret <= 0) {
387 *read = 0;
388 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
389 BIO_set_retry_read(bio);
390 return ret;
391 }
392 *read = ret;
393}

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 331 of file XrdHttpProtocol.cc.

332{
333 if (!data || !bio) {
334 *written = 0;
335 return 0;
336 }
337
338 XrdLink *lp=static_cast<XrdLink *>(BIO_get_data(bio));
339
340 errno = 0;
341 int ret = lp->Send(data, datal);
342 BIO_clear_retry_flags(bio);
343 if (ret <= 0) {
344 *written = 0;
345 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
346 BIO_set_retry_write(bio);
347 return ret;
348 }
349 *written = ret;
350 return 1;
351}

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 69 of file XrdHttpProtocol.cc.

◆ XrdHttpTrace

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