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

Go to the source code of this file.

Namespaces

namespace  XrdHttpProtoInfo
 

Macros

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

Functions

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

Variables

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

Macro Definition Documentation

◆ HTTPS_ALERT

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

Definition at line 980 of file XrdHttpProtocol.cc.

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

◆ TRACELINK [1/3]

#define TRACELINK   lp

Definition at line 220 of file XrdHttpProtocol.cc.

◆ TRACELINK [2/3]

#define TRACELINK   Link

Definition at line 220 of file XrdHttpProtocol.cc.

◆ TRACELINK [3/3]

#define TRACELINK   Link

Definition at line 220 of file XrdHttpProtocol.cc.

◆ TS_Xeq

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

Definition at line 976 of file XrdHttpProtocol.cc.

◆ TS_Xeq3

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

Definition at line 978 of file XrdHttpProtocol.cc.

◆ XRHTTP_TK_GRACETIME

#define XRHTTP_TK_GRACETIME   600

Definition at line 58 of file XrdHttpProtocol.cc.

Function Documentation

◆ BIO_get_data()

void * BIO_get_data ( BIO *  bio)

Definition at line 161 of file XrdHttpProtocol.cc.

161 {
162 return bio->ptr;
163}

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

+ Here is the caller graph for this function:

◆ BIO_get_flags()

int BIO_get_flags ( BIO *  bio)

Definition at line 168 of file XrdHttpProtocol.cc.

168 {
169 return bio->flags;
170}

◆ BIO_get_init()

int BIO_get_init ( BIO *  bio)

Definition at line 175 of file XrdHttpProtocol.cc.

175 {
176 return bio->init;
177}

◆ BIO_get_shutdown()

int BIO_get_shutdown ( BIO *  bio)

Definition at line 184 of file XrdHttpProtocol.cc.

184 {
185 return bio->shutdown;
186}

Referenced by BIO_XrdLink_ctrl(), and BIO_XrdLink_destroy().

+ Here is the caller graph for this function:

◆ BIO_set_data()

void BIO_set_data ( BIO *  bio,
void *  ptr 
)

Definition at line 164 of file XrdHttpProtocol.cc.

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

Referenced by BIO_XrdLink_create().

+ Here is the caller graph for this function:

◆ BIO_set_flags()

void BIO_set_flags ( BIO *  bio,
int  flags 
)

Definition at line 172 of file XrdHttpProtocol.cc.

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

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

+ Here is the caller graph for this function:

◆ BIO_set_init()

void BIO_set_init ( BIO *  bio,
int  init 
)

Definition at line 178 of file XrdHttpProtocol.cc.

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

Referenced by BIO_XrdLink_create(), and BIO_XrdLink_destroy().

+ Here is the caller graph for this function:

◆ BIO_set_shutdown()

void BIO_set_shutdown ( BIO *  bio,
int  shut 
)

Definition at line 181 of file XrdHttpProtocol.cc.

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

Referenced by BIO_XrdLink_ctrl().

+ Here is the caller graph for this function:

◆ BIO_XrdLink_create()

static int BIO_XrdLink_create ( BIO *  bio)
static

Definition at line 408 of file XrdHttpProtocol.cc.

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

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

+ Here is the call graph for this function:

◆ BIO_XrdLink_ctrl()

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

Definition at line 441 of file XrdHttpProtocol.cc.

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

References BIO_get_shutdown(), and BIO_set_shutdown().

+ Here is the call graph for this function:

◆ BIO_XrdLink_destroy()

static int BIO_XrdLink_destroy ( BIO *  bio)
static

Definition at line 427 of file XrdHttpProtocol.cc.

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

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

+ Here is the call graph for this function:

◆ BIO_XrdLink_read()

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

Definition at line 367 of file XrdHttpProtocol.cc.

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

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

+ Here is the call graph for this function:

◆ BIO_XrdLink_write()

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

Definition at line 324 of file XrdHttpProtocol.cc.

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

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

+ Here is the call graph for this function:

◆ XrdVERSIONINFODEF()

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

Variable Documentation

◆ XrdHttpSecEntityTident

const char* XrdHttpSecEntityTident = "http"

Definition at line 66 of file XrdHttpProtocol.cc.

◆ XrdHttpTrace

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