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 static const std::unordered_map<int, std::string> statusTexts = {
1617 {100, "Continue"},
1618 {200, "OK"},
1619 {201, "Created"},
1620 {206, "Partial Content"},
1621 {302, "Redirect"},
1622 {307, "Temporary Redirect"},
1623 {400, "Bad Request"},
1624 {401, "Unauthorized"},
1625 {403, "Forbidden"},
1626 {404, "Not Found"},
1627 {405, "Method Not Allowed"},
1628 {409, "Conflict"},
1629 {416, "Range Not Satisfiable"},
1630 {423, "Locked"},
1631 {500, "Internal Server Error"},
1632 {502, "Bad Gateway"},
1633 {504, "Gateway Timeout"},
1634 {507, "Insufficient Storage"}};
1635
1636 std::stringstream ss;
1637 const std::string crlf = "\r\n";
1638
1639 ss << "HTTP/1.1 " << code << " ";
1640
1641 if (desc) {
1642 ss << desc;
1643 } else {
1644 auto it = statusTexts.find(code);
1645 if (it != statusTexts.end()) {
1646 ss << it->second;
1647 } else {
1648 ss << "Unknown";
1649 }
1650 }
1651 ss << crlf;
1652
1653 if (keepalive && (code != 100))
1654 ss << "Connection: Keep-Alive" << crlf;
1655 else
1656 ss << "Connection: Close" << crlf;
1657
1658 ss << "Server: XrootD/" << XrdVSTRING << crlf;
1659
1660 const auto iter = m_staticheaders.find(CurrentReq.requestverb);
1661 if (iter != m_staticheaders.end()) {
1662 ss << iter->second;
1663 } else {
1664 ss << m_staticheaders[""];
1665 }
1666
1667 if(xrdcors) {
1668 auto corsAllowOrigin = xrdcors->getCORSAllowOriginHeader(CurrentReq.m_origin);
1669 if(corsAllowOrigin) {
1670 ss << *corsAllowOrigin << crlf;
1671 }
1672 }
1673
1674 if ((bodylen >= 0) && (code != 100))
1675 ss << "Content-Length: " << bodylen << crlf;
1676
1677 if (header_to_add && (header_to_add[0] != '\0')) ss << header_to_add << crlf;
1678
1679 ss << crlf;
1680
1681 const std::string &outhdr = ss.str();
1682 TRACEI(RSP, "Sending resp: " << code << " header len:" << outhdr.size());
1683 if (SendData(outhdr.c_str(), outhdr.size()))
1684 return -1;
1685
1686 return 0;
1687}
1688
1689/******************************************************************************/
1690/* S t a r t C h u n k e d R e s p */
1691/******************************************************************************/
1692
1693int XrdHttpProtocol::StartChunkedResp(int code, const char *desc, const char *header_to_add, long long bodylen, bool keepalive) {
1694 const std::string crlf = "\r\n";
1695 std::stringstream ss;
1696
1697 if (header_to_add && (header_to_add[0] != '\0')) {
1698 ss << header_to_add << crlf;
1699 }
1700
1701 ss << "Transfer-Encoding: chunked";
1702 TRACEI(RSP, "Starting chunked response");
1703 return StartSimpleResp(code, desc, ss.str().c_str(), bodylen, keepalive);
1704}
1705
1706/******************************************************************************/
1707/* C h u n k R e s p */
1708/******************************************************************************/
1709
1710int XrdHttpProtocol::ChunkResp(const char *body, long long bodylen) {
1711 long long content_length = (bodylen <= 0) ? (body ? strlen(body) : 0) : bodylen;
1712 if (ChunkRespHeader(content_length))
1713 return -1;
1714
1715 if (body && SendData(body, content_length))
1716 return -1;
1717
1718 return ChunkRespFooter();
1719}
1720
1721/******************************************************************************/
1722/* C h u n k R e s p H e a d e r */
1723/******************************************************************************/
1724
1725int XrdHttpProtocol::ChunkRespHeader(long long bodylen) {
1726 const std::string crlf = "\r\n";
1727 std::stringstream ss;
1728
1729 ss << std::hex << bodylen << std::dec << crlf;
1730
1731 const std::string &chunkhdr = ss.str();
1732 TRACEI(RSP, "Sending encoded chunk of size " << bodylen);
1733 return (SendData(chunkhdr.c_str(), chunkhdr.size())) ? -1 : 0;
1734}
1735
1736/******************************************************************************/
1737/* C h u n k R e s p F o o t e r */
1738/******************************************************************************/
1739
1740int XrdHttpProtocol::ChunkRespFooter() {
1741 const std::string crlf = "\r\n";
1742 return (SendData(crlf.c_str(), crlf.size())) ? -1 : 0;
1743}
1744
1745/******************************************************************************/
1746/* S e n d S i m p l e R e s p */
1747/******************************************************************************/
1748
1752
1753int XrdHttpProtocol::SendSimpleResp(int code, const char *desc, const char *header_to_add, const char *body, long long bodylen, bool keepalive) {
1754
1755 long long content_length = bodylen;
1756 if (bodylen <= 0) {
1757 content_length = body ? strlen(body) : 0;
1758 }
1759
1760 if (StartSimpleResp(code, desc, header_to_add, content_length, keepalive) < 0)
1761 return -1;
1762
1763 //
1764 // Send the data
1765 //
1766 if (body)
1767 return SendData(body, content_length);
1768
1769 return 0;
1770}
1771
1772/******************************************************************************/
1773/* C o n f i g u r e */
1774/******************************************************************************/
1775
1776int XrdHttpProtocol::Configure(char *parms, XrdProtocol_Config * pi) {
1777 /*
1778 Function: Establish configuration at load time.
1779
1780 Input: None.
1781
1782 Output: 0 upon success or !0 otherwise.
1783 */
1784
1785 char *rdf;
1786
1787 // Copy out the special info we want to use at top level
1788 //
1789 eDest.logger(pi->eDest->logger());
1791 // SI = new XrdXrootdStats(pi->Stats);
1792 Sched = pi->Sched;
1793 BPool = pi->BPool;
1794 xrd_cslist = getenv("XRD_CSLIST");
1795
1796 Port = pi->Port;
1797
1798 // Copy out the current TLS context
1799 //
1800 xrdctx = pi->tlsCtx;
1801
1802 {
1803 char buf[16];
1804 sprintf(buf, "%d", Port);
1805 Port_str = strdup(buf);
1806 }
1807
1808 // Now process and configuration parameters
1809 //
1810 rdf = (parms && *parms ? parms : pi->ConfigFN);
1811 if (rdf && Config(rdf, pi->theEnv)) return 0;
1813
1814 // Set the redirect flag if we are a pure redirector
1816 if ((rdf = getenv("XRDROLE"))) {
1817 eDest.Emsg("Config", "XRDROLE: ", rdf);
1818
1819 if (!strcasecmp(rdf, "manager") || !strcasecmp(rdf, "supervisor")) {
1821 eDest.Emsg("Config", "Configured as HTTP(s) redirector.");
1822 } else {
1823
1824 eDest.Emsg("Config", "Configured as HTTP(s) data server.");
1825 }
1826
1827 } else {
1828 eDest.Emsg("Config", "No XRDROLE specified.");
1829 }
1830
1831 // Schedule protocol object cleanup
1832 //
1835 ProtStack.Set((pi->ConnMax / 3 ? pi->ConnMax / 3 : 30), 60 * 60);
1836
1837 // Return success
1838 //
1839
1840 return 1;
1841}
1842
1843/******************************************************************************/
1844/* p a r s e H e a d e r 2 C G I */
1845/******************************************************************************/
1846int XrdHttpProtocol::parseHeader2CGI(XrdOucStream &Config, XrdSysError & err,std::map<std::string, std::string> &header2cgi) {
1847 char *val, keybuf[1024], parmbuf[1024];
1848 char *parm;
1849
1850 // Get the header key
1851 val = Config.GetWord();
1852 if (!val || !val[0]) {
1853 err.Emsg("Config", "No headerkey specified.");
1854 return 1;
1855 } else {
1856
1857 // Trim the beginning, in place
1858 while ( *val && !isalnum(*val) ) val++;
1859 strcpy(keybuf, val);
1860
1861 // Trim the end, in place
1862 char *pp;
1863 pp = keybuf + strlen(keybuf) - 1;
1864 while ( (pp >= keybuf) && (!isalnum(*pp)) ) {
1865 *pp = '\0';
1866 pp--;
1867 }
1868
1869 parm = Config.GetWord();
1870
1871 // Avoids segfault in case a key is given without value
1872 if(!parm || !parm[0]) {
1873 err.Emsg("Config", "No header2cgi value specified. key: '", keybuf, "'");
1874 return 1;
1875 }
1876
1877 // Trim the beginning, in place
1878 while ( *parm && !isalnum(*parm) ) parm++;
1879 strcpy(parmbuf, parm);
1880
1881 // Trim the end, in place
1882 pp = parmbuf + strlen(parmbuf) - 1;
1883 while ( (pp >= parmbuf) && (!isalnum(*pp)) ) {
1884 *pp = '\0';
1885 pp--;
1886 }
1887
1888 // Add this mapping to the map that will be used
1889 try {
1890 header2cgi[keybuf] = parmbuf;
1891 } catch ( ... ) {
1892 err.Emsg("Config", "Can't insert new header2cgi rule. key: '", keybuf, "'");
1893 return 1;
1894 }
1895
1896 }
1897 return 0;
1898}
1899
1900
1901/******************************************************************************/
1902/* I n i t T L S */
1903/******************************************************************************/
1904
1905bool XrdHttpProtocol::InitTLS() {
1906
1907 std::string eMsg;
1910
1911// Create a new TLS context
1912//
1913 if (sslverifydepth > 255) sslverifydepth = 255;
1915 //TLS_SET_REFINT will set the refresh interval in minutes, hence the division by 60
1918
1919// Make sure the context was created
1920//
1921 if (!xrdctx->isOK())
1922 {eDest.Say("Config failure: ", eMsg.c_str());
1923 return false;
1924 }
1925
1926// Setup session cache (this is controversial). The default is off but many
1927// programs expect it being enabled and break when it is disabled. In such
1928// cases it should be enabled. This is, of course, a big OpenSSL mess.
1929//
1930 static const char *sess_ctx_id = "XrdHTTPSessionCtx";
1931 unsigned int n =(unsigned int)(strlen(sess_ctx_id)+1);
1932 xrdctx->SessionCache(tlsCache, sess_ctx_id, n);
1933
1934// Set special ciphers if so specified.
1935//
1937 {eDest.Say("Config failure: ", "Unable to set allowable https ciphers!");
1938 return false;
1939 }
1940
1941// Enable or disable the config in the context
1943
1944// All done
1945//
1946 return true;
1947}
1948
1949/******************************************************************************/
1950/* C l e a n u p */
1951/******************************************************************************/
1952
1953void XrdHttpProtocol::Cleanup() {
1954
1955 TRACE(ALL, " Cleanup");
1956
1957 if (BPool && myBuff) {
1958 BuffConsume(BuffUsed());
1959 BPool->Release(myBuff);
1960 myBuff = 0;
1961 }
1962
1963 if (ssl) {
1964 // Shutdown the SSL/TLS connection
1965 // This triggers a bidirectional shutdown of the connection; the bidirectional
1966 // shutdown is useful to ensure that the client receives the server response;
1967 // a one-sided shutdown can result in the server sending a TCP reset packet, zapping
1968 // the contents of the TCP socket buffer on the client side. The HTTP 1.1 RFC has a
1969 // description of why this is important:
1970 // https://datatracker.ietf.org/doc/html/rfc9112#name-tls-connection-closure
1971 // Once we get the clean SSL shutdown message back from the client, we know that
1972 // the client has received the response and we can safely close the connection.
1973 int ret = SSL_shutdown(ssl);
1974 if (ret != 1) {
1975 if(ret == 0) {
1976 // ret == 0, the unidirectional shutdown was successful; wait for the acknowledgement.
1977 ret = SSL_shutdown(ssl);
1978 if (ret != 1) {
1979 TRACE(ALL, "SSL server failed to receive the SSL shutdown message from the client");
1980 ERR_print_errors(sslbio_err);
1981 }
1982 } else {
1983 //ret < 0, an error really happened.
1984 TRACE(ALL, "SSL server failed to send the shutdown message to the client");
1985 ERR_print_errors(sslbio_err);
1986 }
1987 }
1988
1989 if (secxtractor)
1990 secxtractor->FreeSSL(ssl);
1991
1992 SSL_free(ssl);
1993
1994 }
1995
1996
1997 ssl = 0;
1998 sbio = 0;
1999
2000 if (SecEntity.caps) free(SecEntity.caps);
2001 if (SecEntity.grps) free(SecEntity.grps);
2003 if (SecEntity.vorg) free(SecEntity.vorg);
2004 if (SecEntity.role) free(SecEntity.role);
2005 if (SecEntity.name) free(SecEntity.name);
2006 if (SecEntity.host) free(SecEntity.host);
2008
2009 SecEntity.Reset();
2010
2011 if (Addr_str) free(Addr_str);
2012 Addr_str = 0;
2013}
2014
2015/******************************************************************************/
2016/* R e s e t */
2017/******************************************************************************/
2018
2019void XrdHttpProtocol::Reset() {
2020
2021 TRACE(ALL, " Reset");
2022 Link = 0;
2023 CurrentReq.reset();
2024 CurrentReq.reqstate = 0;
2025
2026 if (myBuff) {
2027 BPool->Release(myBuff);
2028 myBuff = 0;
2029 }
2030 myBuffStart = myBuffEnd = 0;
2031
2032 DoingLogin = false;
2033 DoneSetInfo = false;
2034
2035 ResumeBytes = 0;
2036 Resume = 0;
2037
2038 //
2039 // numReads = 0;
2040 // numReadP = 0;
2041 // numReadV = 0;
2042 // numSegsV = 0;
2043 // numWrites = 0;
2044 // numFiles = 0;
2045 // cumReads = 0;
2046 // cumReadV = 0;
2047 // cumSegsV = 0;
2048 // cumWrites = 0;
2049 // totReadP = 0;
2050
2051 SecEntity.Reset();
2053 ishttps = false;
2054 ssldone = false;
2055
2056 Bridge = 0;
2057 ssl = 0;
2058 sbio = 0;
2059
2060}
2061
2062/******************************************************************************/
2063/* x h t t p s m o d e */
2064/******************************************************************************/
2065
2066/* Function: xhttpsmode
2067
2068 Purpose: To parse the directive: httpsmode {auto | disable | manual}
2069
2070 auto configure https if configured in xrd framework.
2071 disable do not configure https no matter what
2072 manual configure https and ignore the xrd framework
2073
2074 Output: 0 upon success or !0 upon failure.
2075 */
2076
2077int XrdHttpProtocol::xhttpsmode(XrdOucStream & Config) {
2078 char *val;
2079
2080 // Get the val
2081 //
2082 val = Config.GetWord();
2083 if (!val || !val[0]) {
2084 eDest.Emsg("Config", "httpsmode parameter not specified");
2085 return 1;
2086 }
2087
2088 // Record the val
2089 //
2090 if (!strcmp(val, "auto")) httpsmode = hsmAuto;
2091 else if (!strcmp(val, "disable")) httpsmode = hsmOff;
2092 else if (!strcmp(val, "manual")) httpsmode = hsmMan;
2093 else {eDest.Emsg("Config", "invalid httpsmode parameter - ", val);
2094 return 1;
2095 }
2096 return 0;
2097}
2098
2099/******************************************************************************/
2100/* x s s l v e r i f y d e p t h */
2101/******************************************************************************/
2102
2103/* Function: xsslverifydepth
2104
2105 Purpose: To parse the directive: sslverifydepth <depth>
2106
2107 <depth> the max depth of the ssl cert verification
2108
2109 Output: 0 upon success or !0 upon failure.
2110 */
2111
2112int XrdHttpProtocol::xsslverifydepth(XrdOucStream & Config) {
2113 char *val;
2114
2115 // Get the val
2116 //
2117 val = Config.GetWord();
2118 if (!val || !val[0]) {
2119 eDest.Emsg("Config", "sslverifydepth value not specified");
2120 return 1;
2121 }
2122
2123 // Record the val
2124 //
2125 sslverifydepth = atoi(val);
2126
2127 if (xrdctxVer){ HTTPS_ALERT("verifydepth","tlsca",false); }
2128 return 0;
2129}
2130
2131/******************************************************************************/
2132/* x s s l c e r t */
2133/******************************************************************************/
2134
2135/* Function: xsslcert
2136
2137 Purpose: To parse the directive: sslcert <path>
2138
2139 <path> the path of the server certificate to be used.
2140
2141 Output: 0 upon success or !0 upon failure.
2142 */
2143
2144int XrdHttpProtocol::xsslcert(XrdOucStream & Config) {
2145 char *val;
2146
2147 // Get the path
2148 //
2149 val = Config.GetWord();
2150 if (!val || !val[0]) {
2151 eDest.Emsg("Config", "HTTP X509 certificate not specified");
2152 return 1;
2153 }
2154
2155 // Record the path
2156 //
2157 if (sslcert) free(sslcert);
2158 sslcert = strdup(val);
2159
2160 // If we have an xrd context issue reminder
2161 //
2162 HTTPS_ALERT("cert","tls",true);
2163 return 0;
2164}
2165
2166/******************************************************************************/
2167/* x s s l k e y */
2168/******************************************************************************/
2169
2170/* Function: xsslkey
2171
2172 Purpose: To parse the directive: sslkey <path>
2173
2174 <path> the path of the server key to be used.
2175
2176 Output: 0 upon success or !0 upon failure.
2177 */
2178
2179int XrdHttpProtocol::xsslkey(XrdOucStream & Config) {
2180 char *val;
2181
2182 // Get the path
2183 //
2184 val = Config.GetWord();
2185 if (!val || !val[0]) {
2186 eDest.Emsg("Config", "HTTP X509 key not specified");
2187 return 1;
2188 }
2189
2190 // Record the path
2191 //
2192 if (sslkey) free(sslkey);
2193 sslkey = strdup(val);
2194
2195 HTTPS_ALERT("key","tls",true);
2196 return 0;
2197}
2198
2199/******************************************************************************/
2200/* x g m a p */
2201/******************************************************************************/
2202
2203/* Function: xgmap
2204
2205 Purpose: To parse the directive: gridmap [required] [compatNameGeneration] <path>
2206
2207 required optional parameter which if present treats any grimap errors
2208 as fatal.
2209 <path> the path of the gridmap file to be used. Normally it's
2210 /etc/grid-security/gridmap. No mapfile means no translation
2211 required. Pointing to a non existing mapfile is an error.
2212
2213 Output: 0 upon success or !0 upon failure.
2214 */
2215
2216int XrdHttpProtocol::xgmap(XrdOucStream & Config) {
2217 char *val;
2218
2219 // Get the path
2220 //
2221 val = Config.GetWord();
2222 if (!val || !val[0]) {
2223 eDest.Emsg("Config", "HTTP X509 gridmap file location not specified");
2224 return 1;
2225 }
2226
2227 // Handle optional parameter "required"
2228 //
2229 if (!strncmp(val, "required", 8)) {
2230 isRequiredGridmap = true;
2231 val = Config.GetWord();
2232
2233 if (!val || !val[0]) {
2234 eDest.Emsg("Config", "HTTP X509 gridmap file missing after [required] "
2235 "parameter");
2236 return 1;
2237 }
2238 }
2239
2240 // Handle optional parameter "compatNameGeneration"
2241 //
2242 if (!strcmp(val, "compatNameGeneration")) {
2243 compatNameGeneration = true;
2244 val = Config.GetWord();
2245 if (!val || !val[0]) {
2246 eDest.Emsg("Config", "HTTP X509 gridmap file missing after "
2247 "[compatNameGeneration] parameter");
2248 return 1;
2249 }
2250 }
2251
2252
2253 // Record the path
2254 //
2255 if (gridmap) free(gridmap);
2256 gridmap = strdup(val);
2257 return 0;
2258}
2259
2260/******************************************************************************/
2261/* x s s l c a f i l e */
2262/******************************************************************************/
2263
2264/* Function: xsslcafile
2265
2266 Purpose: To parse the directive: sslcafile <path>
2267
2268 <path> the path of the server key to be used.
2269
2270 Output: 0 upon success or !0 upon failure.
2271 */
2272
2273int XrdHttpProtocol::xsslcafile(XrdOucStream & Config) {
2274 char *val;
2275
2276 // Get the path
2277 //
2278 val = Config.GetWord();
2279 if (!val || !val[0]) {
2280 eDest.Emsg("Config", "HTTP X509 CAfile not specified");
2281 return 1;
2282 }
2283
2284 // Record the path
2285 //
2286 if (sslcafile) free(sslcafile);
2287 sslcafile = strdup(val);
2288
2289 if (xrdctxVer){ HTTPS_ALERT("cafile","tlsca",false); }
2290 return 0;
2291}
2292
2293/******************************************************************************/
2294/* x s e c r e t k e y */
2295/******************************************************************************/
2296
2297/* Function: xsecretkey
2298
2299 Purpose: To parse the directive: xsecretkey <key>
2300
2301 <key> the key to be used
2302
2303 Output: 0 upon success or !0 upon failure.
2304 */
2305
2306int XrdHttpProtocol::xsecretkey(XrdOucStream & Config) {
2307 char *val;
2308 bool inFile = false;
2309
2310 // Get the path
2311 //
2312 val = Config.GetWord();
2313 if (!val || !val[0]) {
2314 eDest.Emsg("Config", "Shared secret key not specified");
2315 return 1;
2316 }
2317
2318
2319 // If the token starts with a slash, then we interpret it as
2320 // the path to a file that contains the secretkey
2321 // otherwise, the token itself is the secretkey
2322 if (val[0] == '/') {
2323 struct stat st;
2324 inFile = true;
2325 int fd = open(val, O_RDONLY);
2326
2327 if ( fd == -1 ) {
2328 eDest.Emsg("Config", errno, "open shared secret key file", val);
2329 return 1;
2330 }
2331
2332 if ( fstat(fd, &st) != 0 ) {
2333 eDest.Emsg("Config", errno, "fstat shared secret key file", val);
2334 close(fd);
2335 return 1;
2336 }
2337
2338 if ( st.st_mode & S_IWOTH & S_IWGRP & S_IROTH) {
2339 eDest.Emsg("Config",
2340 "For your own security, the shared secret key file cannot be world readable or group writable '", val, "'");
2341 close(fd);
2342 return 1;
2343 }
2344
2345 FILE *fp = fdopen(fd, "r");
2346
2347 if ( fp == nullptr ) {
2348 eDest.Emsg("Config", errno, "fdopen shared secret key file", val);
2349 close(fd);
2350 return 1;
2351 }
2352
2353 char line[1024];
2354 while( fgets(line, 1024, fp) ) {
2355 char *pp;
2356
2357 // Trim the end
2358 pp = line + strlen(line) - 1;
2359 while ( (pp >= line) && (!isalnum(*pp)) ) {
2360 *pp = '\0';
2361 pp--;
2362 }
2363
2364 // Trim the beginning
2365 pp = line;
2366 while ( *pp && !isalnum(*pp) ) pp++;
2367
2368 if ( strlen(pp) >= 32 ) {
2369 eDest.Say("Config", "Secret key loaded.");
2370 // Record the path
2371 if (secretkey) free(secretkey);
2372 secretkey = strdup(pp);
2373
2374 fclose(fp);
2375 return 0;
2376 }
2377
2378 }
2379
2380 fclose(fp);
2381 eDest.Emsg("Config", "Cannot find useful secretkey in file '", val, "'");
2382 return 1;
2383
2384 }
2385
2386 if ( strlen(val) < 32 ) {
2387 eDest.Emsg("Config", "Secret key is too short");
2388 return 1;
2389 }
2390
2391 // Record the path
2392 if (secretkey) free(secretkey);
2393 secretkey = strdup(val);
2394 if (!inFile) Config.noEcho();
2395
2396 return 0;
2397}
2398
2399/******************************************************************************/
2400/* x l i s t d e n y */
2401/******************************************************************************/
2402
2403/* Function: xlistdeny
2404
2405 Purpose: To parse the directive: listingdeny <yes|no|0|1>
2406
2407 <val> makes this redirector deny listings with an error
2408
2409 Output: 0 upon success or !0 upon failure.
2410 */
2411
2412int XrdHttpProtocol::xlistdeny(XrdOucStream & Config) {
2413 char *val;
2414
2415 // Get the path
2416 //
2417 val = Config.GetWord();
2418 if (!val || !val[0]) {
2419 eDest.Emsg("Config", "listingdeny flag not specified");
2420 return 1;
2421 }
2422
2423 // Record the value
2424 //
2425 listdeny = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2426
2427
2428 return 0;
2429}
2430
2431/******************************************************************************/
2432/* x l i s t r e d i r */
2433/******************************************************************************/
2434
2435/* Function: xlistredir
2436
2437 Purpose: To parse the directive: listingredir <Url>
2438
2439 <Url> http/https server to redirect to in the case of listing
2440
2441 Output: 0 upon success or !0 upon failure.
2442 */
2443
2444int XrdHttpProtocol::xlistredir(XrdOucStream & Config) {
2445 char *val;
2446
2447 // Get the path
2448 //
2449 val = Config.GetWord();
2450 if (!val || !val[0]) {
2451 eDest.Emsg("Config", "listingredir flag not specified");
2452 return 1;
2453 }
2454
2455 // Record the value
2456 //
2457 if (listredir) free(listredir);
2458 listredir = strdup(val);
2459
2460
2461 return 0;
2462}
2463
2464/******************************************************************************/
2465/* x s s l d e s t h t t p s */
2466/******************************************************************************/
2467
2468/* Function: xdesthttps
2469
2470 Purpose: To parse the directive: desthttps <yes|no|0|1>
2471
2472 <val> makes this redirector produce http or https redirection targets
2473
2474 Output: 0 upon success or !0 upon failure.
2475 */
2476
2477int XrdHttpProtocol::xdesthttps(XrdOucStream & Config) {
2478 char *val;
2479
2480 // Get the path
2481 //
2482 val = Config.GetWord();
2483 if (!val || !val[0]) {
2484 eDest.Emsg("Config", "desthttps flag not specified");
2485 return 1;
2486 }
2487
2488 // Record the value
2489 //
2490 isdesthttps = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2491
2492
2493 return 0;
2494}
2495
2496/******************************************************************************/
2497/* x e m b e d d e d s t a t i c */
2498/******************************************************************************/
2499
2500/* Function: xembeddedstatic
2501
2502 Purpose: To parse the directive: embeddedstatic <yes|no|0|1|true|false>
2503
2504 <val> this server will redirect HTTPS to itself using HTTP+token
2505
2506 Output: 0 upon success or !0 upon failure.
2507 */
2508
2509int XrdHttpProtocol::xembeddedstatic(XrdOucStream & Config) {
2510 char *val;
2511
2512 // Get the path
2513 //
2514 val = Config.GetWord();
2515 if (!val || !val[0]) {
2516 eDest.Emsg("Config", "embeddedstatic flag not specified");
2517 return 1;
2518 }
2519
2520 // Record the value
2521 //
2522 embeddedstatic = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2523
2524
2525 return 0;
2526}
2527
2528/******************************************************************************/
2529/* x r e d i r s t a t i c */
2530/******************************************************************************/
2531
2532/* Function: xstaticredir
2533
2534 Purpose: To parse the directive: staticredir <Url>
2535
2536 <Url> http/https server to redirect to in the case of /static
2537
2538 Output: 0 upon success or !0 upon failure.
2539 */
2540
2541int XrdHttpProtocol::xstaticredir(XrdOucStream & Config) {
2542 char *val;
2543
2544 // Get the path
2545 //
2546 val = Config.GetWord();
2547 if (!val || !val[0]) {
2548 eDest.Emsg("Config", "staticredir url not specified");
2549 return 1;
2550 }
2551
2552 // Record the value
2553 //
2554 if (staticredir) free(staticredir);
2555 staticredir = strdup(val);
2556
2557 return 0;
2558}
2559
2560/******************************************************************************/
2561/* x p r e l o a d s t a t i c */
2562/******************************************************************************/
2563
2564/* Function: xpreloadstatic
2565
2566 Purpose: To parse the directive: preloadstatic <http url path> <local file>
2567
2568 <http url path> http/http path whose response we are preloading
2569 e.g. /static/mycss.css
2570 NOTE: this must start with /static
2571
2572
2573 Output: 0 upon success or !0 upon failure.
2574 */
2575
2576int XrdHttpProtocol::xstaticpreload(XrdOucStream & Config) {
2577 char *val, *k, key[1024];
2578
2579 // Get the key
2580 //
2581 k = Config.GetWord();
2582 if (!k || !k[0]) {
2583 eDest.Emsg("Config", "preloadstatic urlpath not specified");
2584 return 1;
2585 }
2586
2587 strcpy(key, k);
2588
2589 // Get the val
2590 //
2591 val = Config.GetWord();
2592 if (!val || !val[0]) {
2593 eDest.Emsg("Config", "preloadstatic filename not specified");
2594 return 1;
2595 }
2596
2597 // Try to load the file into memory
2598 int fp = open(val, O_RDONLY);
2599 if( fp < 0 ) {
2600 eDest.Emsg("Config", errno, "open preloadstatic filename", val);
2601 return 1;
2602 }
2603
2604 StaticPreloadInfo *nfo = new StaticPreloadInfo;
2605 // Max 64Kb ok?
2606 nfo->data = (char *)malloc(65536);
2607 nfo->len = read(fp, (void *)nfo->data, 65536);
2608 close(fp);
2609
2610 if (nfo->len <= 0) {
2611 eDest.Emsg("Config", errno, "read from preloadstatic filename", val);
2612 return 1;
2613 }
2614
2615 if (nfo->len >= 65536) {
2616 eDest.Emsg("Config", "Truncated preloadstatic filename. Max is 64 KB '", val, "'");
2617 return 1;
2618 }
2619
2620 // Record the value
2621 //
2622 if (!staticpreload)
2624
2625 staticpreload->Rep((const char *)key, nfo);
2626 return 0;
2627}
2628
2629/******************************************************************************/
2630/* x s t a t i c h e a d e r */
2631/******************************************************************************/
2632
2633//
2634// xstaticheader parses the http.staticheader director with the following syntax:
2635//
2636// http.staticheader [-verb=[GET|HEAD|...]]* header [value]
2637//
2638// When set, this will cause XrdHttp to always return the specified header and
2639// value.
2640//
2641// Setting this option multiple times is additive (multiple headers may be set).
2642// Omitting the value will cause the static header setting to be unset.
2643//
2644// Omitting the -verb argument will cause it the header to be set unconditionally
2645// for all requests.
2646int XrdHttpProtocol::xstaticheader(XrdOucStream & Config) {
2647 auto val = Config.GetWord();
2648 std::vector<std::string> verbs;
2649 while (true) {
2650 if (!val || !val[0]) {
2651 eDest.Emsg("Config", "http.staticheader requires the header to be specified");
2652 return 1;
2653 }
2654
2655 std::string match_verb;
2656 std::string_view val_str(val);
2657 if (val_str.substr(0, 6) == "-verb=") {
2658 verbs.emplace_back(val_str.substr(6));
2659 } else if (val_str == "-") {
2660 eDest.Emsg("Config", "http.staticheader is ignoring unknown flag: ", val_str.data());
2661 } else {
2662 break;
2663 }
2664
2665 val = Config.GetWord();
2666 }
2667 if (verbs.empty()) {
2668 verbs.emplace_back();
2669 }
2670
2671 std::string header = val;
2672
2673 val = Config.GetWord();
2674 std::string header_value;
2675 if (val && val[0]) {
2676 header_value = val;
2677 }
2678
2679 for (const auto &verb : verbs) {
2680 auto iter = m_staticheader_map.find(verb);
2681 if (iter == m_staticheader_map.end()) {
2682 if (!header_value.empty())
2683 m_staticheader_map.insert(iter, {verb, {{header, header_value}}});
2684 } else if (header_value.empty()) {
2685 iter->second.clear();
2686 } else {
2687 iter->second.emplace_back(header, header_value);
2688 }
2689 }
2690
2691 return 0;
2692}
2693
2694
2695/******************************************************************************/
2696/* x s e l f h t t p s 2 h t t p */
2697/******************************************************************************/
2698
2699/* Function: selfhttps2http
2700
2701 Purpose: To parse the directive: selfhttps2http <yes|no|0|1>
2702
2703 <val> this server will redirect HTTPS to itself using HTTP+token
2704
2705 Output: 0 upon success or !0 upon failure.
2706 */
2707
2708int XrdHttpProtocol::xselfhttps2http(XrdOucStream & Config) {
2709 char *val;
2710
2711 // Get the path
2712 //
2713 val = Config.GetWord();
2714 if (!val || !val[0]) {
2715 eDest.Emsg("Config", "selfhttps2http flag not specified");
2716 return 1;
2717 }
2718
2719 // Record the value
2720 //
2721 selfhttps2http = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2722
2723
2724 return 0;
2725}
2726
2727/******************************************************************************/
2728/* x s e c x t r a c t o r */
2729/******************************************************************************/
2730
2731/* Function: xsecxtractor
2732
2733 Purpose: To parse the directive: secxtractor [required] <path> <params>
2734
2735 required optional parameter which if present treats any secxtractor
2736 errors as fatal.
2737 <path> the path of the plugin to be loaded
2738 <params> parameters passed to the secxtractor library
2739
2740 Output: 0 upon success or !0 upon failure.
2741 */
2742
2743int XrdHttpProtocol::xsecxtractor(XrdOucStream& Config) {
2744 char *val;
2745
2746 // Get the path
2747 //
2748 val = Config.GetWord();
2749 if (!val || !val[0]) {
2750 eDest.Emsg("Config", "No security extractor plugin specified.");
2751 return 1;
2752 } else {
2753 // Handle optional parameter [required]
2754 //
2755 if (!strncmp(val, "required", 8)) {
2756 isRequiredXtractor = true;
2757 val = Config.GetWord();
2758
2759 if (!val || !val[0]) {
2760 eDest.Emsg("Config", "No security extractor plugin after [required] "
2761 "parameter");
2762 return 1;
2763 }
2764 }
2765
2766 char libName[4096];
2767 strlcpy(libName, val, sizeof(libName));
2768 libName[sizeof(libName) - 1] = '\0';
2769 char libParms[4096];
2770
2771 if (!Config.GetRest(libParms, 4095)) {
2772 eDest.Emsg("Config", "secxtractor config params longer than 4k");
2773 return 1;
2774 }
2775
2776 // Try to load the plugin (if available) that extracts info from the
2777 // user cert/proxy
2778 if (LoadSecXtractor(&eDest, libName, libParms)) {
2779 return 1;
2780 }
2781 }
2782
2783 return 0;
2784}
2785
2786int XrdHttpProtocol::xcors(XrdOucStream& Config) {
2787 char * val;
2788 // Get the path
2789 val = Config.GetWord();
2790 if (!val || !val[0]) {
2791 eDest.Emsg("Config", "No CORS plugin specified.");
2792 return 1;
2793 }
2794 xrdcorsLibPath = val;
2795 return 0;
2796}
2797
2798/******************************************************************************/
2799/* x e x t h a n d l e r */
2800/******************************************************************************/
2801
2802/* Function: xexthandler
2803 *
2804 * Purpose: To parse the directive: exthandler <name> <path> <initparm>
2805 *
2806 * <name> a unique name (max 16chars) to be given to this
2807 * instance, e.g 'myhandler1'
2808 * <path> the path of the plugin to be loaded
2809 * <initparm> a string parameter (e.g. a config file) that is
2810 * passed to the initialization of the plugin
2811 *
2812 * Output: 0 upon success or !0 upon failure.
2813 */
2814
2815int XrdHttpProtocol::xexthandler(XrdOucStream &Config,
2816 std::vector<extHInfo> &hiVec) {
2817 char *val, path[1024], namebuf[1024];
2818 char *parm;
2819 // By default, every external handler need TLS configured to be loaded
2820 bool noTlsOK = false;
2821
2822 // Get the name
2823 //
2824 val = Config.GetWord();
2825 if (!val || !val[0]) {
2826 eDest.Emsg("Config", "No instance name specified for an http external handler plugin.");
2827 return 1;
2828 }
2829 if (strlen(val) >= 16) {
2830 eDest.Emsg("Config", "Instance name too long for an http external handler plugin.");
2831 return 1;
2832 }
2833 strncpy(namebuf, val, sizeof(namebuf));
2834 namebuf[ sizeof(namebuf)-1 ] = '\0';
2835
2836 // Get the +notls option if it was provided
2837 val = Config.GetWord();
2838
2839 if(val && !strcmp("+notls",val)) {
2840 noTlsOK = true;
2841 val = Config.GetWord();
2842 }
2843
2844 // Get the path
2845 //
2846 if (!val || !val[0]) {
2847 eDest.Emsg("Config", "No http external handler plugin specified.");
2848 return 1;
2849 }
2850 if (strlen(val) >= (int)sizeof(path)) {
2851 eDest.Emsg("Config", "Path too long for an http external handler plugin.");
2852 return 1;
2853 }
2854
2855 strcpy(path, val);
2856
2857 // Everything else is a free string
2858 //
2859 parm = Config.GetWord();
2860
2861 // Verify whether this is a duplicate (we never supported replacements)
2862 //
2863 for (int i = 0; i < (int)hiVec.size(); i++)
2864 {if (hiVec[i].extHName == namebuf) {
2865 eDest.Emsg("Config", "Instance name already present for "
2866 "http external handler plugin",
2867 hiVec[i].extHPath.c_str());
2868 return 1;
2869 }
2870 }
2871
2872 // Verify that we don't have more already than we are allowed to have
2873 //
2874 if (hiVec.size() >= MAX_XRDHTTPEXTHANDLERS) {
2875 eDest.Emsg("Config", "Cannot load one more exthandler. Max is 4");
2876 return 1;
2877 }
2878
2879 // Create an info struct and push it on the list of ext handlers to load
2880 //
2881 hiVec.push_back(extHInfo(namebuf, path, (parm ? parm : ""), noTlsOK));
2882
2883 return 0;
2884}
2885
2886/******************************************************************************/
2887/* x h e a d e r 2 c g i */
2888/******************************************************************************/
2889
2890/* Function: xheader2cgi
2891 *
2892 * Purpose: To parse the directive: header2cgi <headerkey> <cgikey>
2893 *
2894 * <headerkey> the name of an incoming HTTP header
2895 * to be transformed
2896 * <cgikey> the name to be given when adding it to the cgi info
2897 * that is kept only internally
2898 *
2899 * Output: 0 upon success or !0 upon failure.
2900 */
2901
2902int XrdHttpProtocol::xheader2cgi(XrdOucStream & Config) {
2903 return parseHeader2CGI(Config,eDest,hdr2cgimap);
2904}
2905
2906/******************************************************************************/
2907/* x s s l c a d i r */
2908/******************************************************************************/
2909
2910/* Function: xsslcadir
2911
2912 Purpose: To parse the directive: sslcadir <path>
2913
2914 <path> the path of the server key to be used.
2915
2916 Output: 0 upon success or !0 upon failure.
2917 */
2918
2919int XrdHttpProtocol::xsslcadir(XrdOucStream & Config) {
2920 char *val;
2921
2922 // Get the path
2923 //
2924 val = Config.GetWord();
2925 if (!val || !val[0]) {
2926 eDest.Emsg("Config", "HTTP X509 CAdir not specified");
2927 return 1;
2928 }
2929
2930 // Record the path
2931 //
2932 if (sslcadir) free(sslcadir);
2933 sslcadir = strdup(val);
2934
2935 if (xrdctxVer){ HTTPS_ALERT("cadir","tlsca",false); }
2936 return 0;
2937}
2938
2939/******************************************************************************/
2940/* x s s l c i p h e r f i l t e r */
2941/******************************************************************************/
2942
2943/* Function: xsslcipherfilter
2944
2945 Purpose: To parse the directive: cipherfilter <filter>
2946
2947 <filter> the filter string to be used when generating
2948 the SSL cipher list
2949
2950 Output: 0 upon success or !0 upon failure.
2951 */
2952
2953int XrdHttpProtocol::xsslcipherfilter(XrdOucStream & Config) {
2954 char *val;
2955
2956 // Get the filter string
2957 //
2958 val = Config.GetWord();
2959 if (!val || !val[0]) {
2960 eDest.Emsg("Config", "SSL cipherlist filter string not specified");
2961 return 1;
2962 }
2963
2964 // Record the filter string
2965 //
2967 sslcipherfilter = strdup(val);
2968
2969 return 0;
2970}
2971
2972/******************************************************************************/
2973/* x t l s r e u s e */
2974/******************************************************************************/
2975
2976/* Function: xtlsreuse
2977
2978 Purpose: To parse the directive: tlsreuse {on | off}
2979
2980 Output: 0 upon success or 1 upon failure.
2981 */
2982
2983int XrdHttpProtocol::xtlsreuse(XrdOucStream & Config) {
2984
2985 char *val;
2986
2987// Get the argument
2988//
2989 val = Config.GetWord();
2990 if (!val || !val[0])
2991 {eDest.Emsg("Config", "tlsreuse argument not specified"); return 1;}
2992
2993// If it's off, we set it off
2994//
2995 if (!strcmp(val, "off"))
2997 return 0;
2998 }
2999
3000// If it's on we set it on.
3001//
3002 if (!strcmp(val, "on"))
3004 return 0;
3005 }
3006
3007// Bad argument
3008//
3009 eDest.Emsg("config", "invalid tlsreuse parameter -", val);
3010 return 1;
3011}
3012
3013int XrdHttpProtocol::xtlsclientauth(XrdOucStream &Config) {
3014 auto val = Config.GetWord();
3015 if (!val || !val[0])
3016 {eDest.Emsg("Config", "tlsclientauth argument not specified"); return 1;}
3017
3018 if (!strcmp(val, "off"))
3019 {tlsClientAuth = false;
3020 return 0;
3021 }
3022 if (!strcmp(val, "on"))
3023 {tlsClientAuth = true;
3024 return 0;
3025 }
3026
3027 eDest.Emsg("config", "invalid tlsclientauth parameter -", val);
3028 return 1;
3029}
3030
3031int XrdHttpProtocol::xauth(XrdOucStream &Config) {
3032 char *val = Config.GetWord();
3033 if(val) {
3034 if(!strcmp("tpc",val)) {
3035 if(!(val = Config.GetWord())) {
3036 eDest.Emsg("Config", "http.auth tpc value not specified."); return 1;
3037 } else {
3038 if(!strcmp("fcreds",val)) {
3039 tpcForwardCreds = true;
3040 } else {
3041 eDest.Emsg("Config", "http.auth tpc value is invalid"); return 1;
3042 }
3043 }
3044 } else {
3045 eDest.Emsg("Config", "http.auth value is invalid"); return 1;
3046 }
3047 }
3048 return 0;
3049}
3050
3051int XrdHttpProtocol::xmaxdelay(XrdOucStream &Config) {
3052 char *val = Config.GetWord();
3053 if(val) {
3054 int maxdelay;
3055 if (XrdOuca2x::a2tm(eDest, "http.maxdelay", val, &maxdelay, 1)) return 1;
3056 m_maxdelay = maxdelay;
3057 } else {
3058 eDest.Emsg("Config", "http.maxdelay requires an argument in seconds (default is 30). Example: http.maxdelay 30");
3059 return 1;
3060 }
3061 return 0;
3062}
3063
3064/******************************************************************************/
3065/* x t r a c e */
3066/******************************************************************************/
3067
3068/* Function: xtrace
3069
3070 Purpose: To parse the directive: trace <events>
3071
3072 <events> the blank separated list of events to trace. Trace
3073 directives are cumulative.
3074
3075 Output: 0 upon success or 1 upon failure.
3076 */
3077
3078int XrdHttpProtocol::xtrace(XrdOucStream & Config) {
3079
3080 char *val;
3081
3082 static struct traceopts {
3083 const char *opname;
3084 int opval;
3085 } tropts[] = {
3086 {"all", TRACE_ALL},
3087 {"auth", TRACE_AUTH},
3088 {"debug", TRACE_DEBUG},
3089 {"mem", TRACE_MEM},
3090 {"redirect", TRACE_REDIR},
3091 {"request", TRACE_REQ},
3092 {"response", TRACE_RSP}
3093 };
3094 int i, neg, trval = 0, numopts = sizeof (tropts) / sizeof (struct traceopts);
3095
3096 if (!(val = Config.GetWord())) {
3097 eDest.Emsg("config", "trace option not specified");
3098 return 1;
3099 }
3100 while (val) {
3101 if (!strcmp(val, "off")) trval = 0;
3102 else {
3103 if ((neg = (val[0] == '-' && val[1]))) val++;
3104 for (i = 0; i < numopts; i++) {
3105 if (!strcmp(val, tropts[i].opname)) {
3106 if (neg) trval &= ~tropts[i].opval;
3107 else trval |= tropts[i].opval;
3108 break;
3109 }
3110 }
3111 if (i >= numopts)
3112 eDest.Emsg("config", "invalid trace option", val);
3113 }
3114 val = Config.GetWord();
3115 }
3116 XrdHttpTrace.What = trval;
3117 return 0;
3118}
3119
3120int XrdHttpProtocol::doStat(char *fname) {
3121 int l;
3122 bool b;
3123 CurrentReq.filesize = 0;
3126
3127 memset(&CurrentReq.xrdreq, 0, sizeof (ClientRequest));
3129 memset(CurrentReq.xrdreq.stat.reserved, 0,
3130 sizeof (CurrentReq.xrdreq.stat.reserved));
3131 l = strlen(fname) + 1;
3132 CurrentReq.xrdreq.stat.dlen = htonl(l);
3133
3134 if (!Bridge) return -1;
3135 b = Bridge->Run((char *) &CurrentReq.xrdreq, fname, l);
3136 if (!b) {
3137 return -1;
3138 }
3139
3140
3141 return 0;
3142}
3143
3144/******************************************************************************/
3145/* d o C h k s u m */
3146/******************************************************************************/
3147
3148int XrdHttpProtocol::doChksum(const XrdOucString &fname) {
3149 size_t length;
3150 memset(&CurrentReq.xrdreq, 0, sizeof (ClientRequest));
3156 length = fname.length() + 1;
3157 CurrentReq.xrdreq.query.dlen = htonl(length);
3158
3159 if (!Bridge) return -1;
3160
3161 return Bridge->Run(reinterpret_cast<char *>(&CurrentReq.xrdreq), const_cast<char *>(fname.c_str()), length) ? 0 : -1;
3162}
3163
3164
3165static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION);
3166
3167// Loads the SecXtractor plugin, if available
3168int XrdHttpProtocol::LoadSecXtractor(XrdSysError *myeDest, const char *libName,
3169 const char *libParms) {
3170
3171
3172 // We don't want to load it more than once
3173 if (secxtractor) return 1;
3174
3175 XrdOucPinLoader myLib(myeDest, &compiledVer, "secxtractorlib", libName);
3177
3178 // Get the entry point of the object creator
3179 //
3180 ep = (XrdHttpSecXtractor *(*)(XrdHttpSecXtractorArgs))(myLib.Resolve("XrdHttpGetSecXtractor"));
3181 if (ep && (secxtractor = ep(myeDest, NULL, libParms))) return 0;
3182 myLib.Unload();
3183 return 1;
3184}
3185/******************************************************************************/
3186/* L o a d E x t H a n d l e r */
3187/******************************************************************************/
3188
3189int XrdHttpProtocol::LoadExtHandlerNoTls(std::vector<extHInfo> &hiVec, const char *cFN, XrdOucEnv &myEnv) {
3190 for (int i = 0; i < (int) hiVec.size(); i++) {
3191 if(hiVec[i].extHNoTlsOK) {
3192 // The external plugin does not need TLS to be loaded
3193 if (LoadExtHandler(&eDest, hiVec[i].extHPath.c_str(), cFN,
3194 hiVec[i].extHParm.c_str(), &myEnv,
3195 hiVec[i].extHName.c_str()))
3196 return 1;
3197 }
3198 }
3199 return 0;
3200}
3201
3202int XrdHttpProtocol::LoadExtHandler(std::vector<extHInfo> &hiVec,
3203 const char *cFN, XrdOucEnv &myEnv) {
3204
3205 // Add the pointer to the cadir and the cakey to the environment.
3206 //
3207 if (sslcadir) myEnv.Put("http.cadir", sslcadir);
3208 if (sslcafile) myEnv.Put("http.cafile", sslcafile);
3209 if (sslcert) myEnv.Put("http.cert", sslcert);
3210 if (sslkey) myEnv.Put("http.key" , sslkey);
3211
3212 // Load all of the specified external handlers.
3213 //
3214 for (int i = 0; i < (int)hiVec.size(); i++) {
3215 // Only load the external handlers that were not already loaded
3216 // by LoadExtHandlerNoTls(...)
3217 if(!ExtHandlerLoaded(hiVec[i].extHName.c_str())) {
3218 if (LoadExtHandler(&eDest, hiVec[i].extHPath.c_str(), cFN,
3219 hiVec[i].extHParm.c_str(), &myEnv,
3220 hiVec[i].extHName.c_str())) return 1;
3221 }
3222 }
3223 return 0;
3224}
3225
3226// Loads the external handler plugin, if available
3227int XrdHttpProtocol::LoadExtHandler(XrdSysError *myeDest, const char *libName,
3228 const char *configFN, const char *libParms,
3229 XrdOucEnv *myEnv, const char *instName) {
3230
3231
3232 // This function will avoid loading doubles. No idea why this happens
3233 if (ExtHandlerLoaded(instName)) {
3234 eDest.Emsg("Config", "Instance name already present for an http external handler plugin.");
3235 return 1;
3236 }
3237 if (exthandlercnt >= MAX_XRDHTTPEXTHANDLERS) {
3238 eDest.Emsg("Config", "Cannot load one more exthandler. Max is 4");
3239 return 1;
3240 }
3241
3242 XrdOucPinLoader myLib(myeDest, &compiledVer, "exthandlerlib", libName);
3244
3245 // Get the entry point of the object creator
3246 //
3247 ep = (XrdHttpExtHandler *(*)(XrdHttpExtHandlerArgs))(myLib.Resolve("XrdHttpGetExtHandler"));
3248
3249 XrdHttpExtHandler *newhandler;
3250 if (ep && (newhandler = ep(myeDest, configFN, libParms, myEnv))) {
3251
3252 // Handler has been loaded, it's the last one in the list
3253 strncpy( exthandler[exthandlercnt].name, instName, 16 );
3254 exthandler[exthandlercnt].name[15] = '\0';
3255 exthandler[exthandlercnt++].ptr = newhandler;
3256
3257 return 0;
3258 }
3259
3260 myLib.Unload();
3261 return 1;
3262}
3263
3264
3265int XrdHttpProtocol::LoadCorsHandler(XrdSysError *eDest, const char *libname) {
3266 if(xrdcors) return 1;
3267 XrdOucPinLoader corsLib(eDest, &compiledVer, "corslib",libname);
3269 ep = (XrdHttpCors *(*)(XrdHttpCorsGetHandlerArgs))(corsLib.Resolve("XrdHttpCorsGetHandler"));
3270 if(ep && (xrdcors = ep())) return 0;
3271 corsLib.Unload();
3272 return 1;
3273}
3274
3275// Tells if we have already loaded a certain exthandler. Try to
3276// privilege speed, as this func may be invoked pretty often
3277bool XrdHttpProtocol::ExtHandlerLoaded(const char *handlername) {
3278 for (int i = 0; i < exthandlercnt; i++) {
3279 if ( !strncmp(exthandler[i].name, handlername, 15) ) {
3280 return true;
3281 }
3282 }
3283 return false;
3284}
3285
3286// Locates a matching external handler for a given request, if available. Try to
3287// privilege speed, as this func is invoked for every incoming request
3288XrdHttpExtHandler * XrdHttpProtocol::FindMatchingExtHandler(const XrdHttpReq &req) {
3289
3290 for (int i = 0; i < exthandlercnt; i++) {
3291 if (exthandler[i].ptr->MatchesPath(req.requestverb.c_str(), req.resource.c_str())) {
3292 return exthandler[i].ptr;
3293 }
3294 }
3295 return NULL;
3296}
#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
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"  )