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