978 {
981 std::vector<extHInfo> extHIVec;
982 char *var;
983 int cfgFD, GoNo, NoGo = 0, ismine;
984
985 var = nullptr;
988
989 pmarkHandle = (
XrdNetPMark* ) myEnv->GetPtr(
"XrdNetPMark*");
990
991 cksumHandler.configure(xrd_cslist);
992 auto nonIanaChecksums = cksumHandler.getNonIANAConfiguredCksums();
993 if(nonIanaChecksums.size()) {
994 std::stringstream warningMsgSS;
995 warningMsgSS << "Config warning: the following checksum algorithms are not IANA compliant: [";
996 std::string unknownCksumString;
997 for(auto unknownCksum: nonIanaChecksums) {
998 unknownCksumString += unknownCksum + ",";
999 }
1000 unknownCksumString.erase(unknownCksumString.size() - 1);
1001 warningMsgSS << unknownCksumString << "]" << ". They therefore cannot be queried by a user via HTTP." ;
1002 eDest.
Say(warningMsgSS.str().c_str());
1003 }
1004
1005
1006 if (!m_bio_type) {
1007
1008 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1009 m_bio_type = (26|0x0400|0x0100);
1010 m_bio_method = static_cast<BIO_METHOD*>(OPENSSL_malloc(sizeof(BIO_METHOD)));
1011
1012 if (m_bio_method) {
1013 memset(m_bio_method, '\0', sizeof(BIO_METHOD));
1014 m_bio_method->type = m_bio_type;
1020 }
1021 #else
1022
1023
1024 m_bio_type = BIO_get_new_index();
1025 m_bio_method = BIO_meth_new(m_bio_type, "xrdhttp-bio-method");
1026
1027 if (m_bio_method) {
1033 }
1034
1035 #endif
1036 }
1037
1038
1039
1040
1042
1043
1044
1045 if ((cfgFD =
open(ConfigFN, O_RDONLY, 0)) < 0)
1046 return eDest.
Emsg(
"Config", errno,
"open config file", ConfigFN);
1048 static const char *cvec[] = { "*** http protocol config:", 0 };
1050
1051
1052
1053 while ((var =
Config.GetMyFirstWord())) {
1054 if ((ismine = !strncmp("http.", var, 5)) && var[5]) var += 5;
1055
1056 if (ismine) {
1057 if TS_Xeq(
"trace", xtrace);
1058 else if TS_Xeq(
"cert", xsslcert);
1059 else if TS_Xeq(
"key", xsslkey);
1060 else if TS_Xeq(
"cadir", xsslcadir);
1061 else if TS_Xeq(
"cipherfilter", xsslcipherfilter);
1062 else if TS_Xeq(
"gridmap", xgmap);
1063 else if TS_Xeq(
"cafile", xsslcafile);
1064 else if TS_Xeq(
"secretkey", xsecretkey);
1065 else if TS_Xeq(
"desthttps", xdesthttps);
1066 else if TS_Xeq(
"secxtractor", xsecxtractor);
1067 else if TS_Xeq3(
"exthandler", xexthandler);
1068 else if TS_Xeq(
"selfhttps2http", xselfhttps2http);
1069 else if TS_Xeq(
"embeddedstatic", xembeddedstatic);
1070 else if TS_Xeq(
"listingredir", xlistredir);
1071 else if TS_Xeq(
"staticredir", xstaticredir);
1072 else if TS_Xeq(
"staticpreload", xstaticpreload);
1073 else if TS_Xeq(
"listingdeny", xlistdeny);
1074 else if TS_Xeq(
"header2cgi", xheader2cgi);
1075 else if TS_Xeq(
"httpsmode", xhttpsmode);
1076 else if TS_Xeq(
"tlsreuse", xtlsreuse);
1077 else if TS_Xeq(
"auth", xauth);
1078 else {
1079 eDest.
Say(
"Config warning: ignoring unknown directive '", var,
"'.");
1081 continue;
1082 }
1083 if (GoNo) {
1085 NoGo = 1;
1086 }
1087 }
1088 }
1089
1090
1091
1092
1093 if (NoGo)
1094 {
eDest.
Say(
"Config failure: one or more directives are flawed!");
1095 return 1;
1096 }
1097
1098
1099
1100 hdr2cgimap["Cache-Control"] = "cache-control";
1101
1102
1103 if (getenv(
"XRDCL_EC"))
usingEC =
true;
1104
1105
1106
1107
1108
1109
1112 : "was not configured.");
1113 const char *what = Configed();
1114
1115 eDest.
Say(
"Config warning: HTTPS functionality ", why);
1117
1118 LoadExtHandlerNoTls(extHIVec, ConfigFN, *myEnv);
1119 if (what)
1120 {
eDest.
Say(
"Config failure: ", what,
" HTTPS but it ", why);
1121 NoGo = 1;
1122 }
1123 return NoGo;
1124 }
1125
1126
1127
1128
1129 if (sslkey && !sslcert)
1130 {
eDest.
Say(
"Config warning: specifying http.key without http.cert "
1131 "is meaningless; ignoring key!");
1132 free(sslkey); sslkey = 0;
1133 }
1134
1135
1136
1138 {if (!sslcert)
1139 {
eDest.
Say(
"Config failure: 'httpsmode manual' requires atleast a "
1140 "a cert specification!");
1141 return 1;
1142 }
1143 }
1144
1145
1146
1147
1148
1151 const char *what1 = 0, *what2 = 0, *what3 = 0;
1152
1153 if (!sslcert && cP->
cert.size())
1154 {sslcert = strdup(cP->
cert.c_str());
1155 if (cP->
pkey.size()) sslkey = strdup(cP->
pkey.c_str());
1156 what1 = "xrd.tls to supply 'cert' and 'key'.";
1157 }
1158 if (!sslcadir && cP->
cadir.size())
1159 {sslcadir = strdup(cP->
cadir.c_str());
1160 what2 = "xrd.tlsca to supply 'cadir'.";
1161 }
1162 if (!sslcafile && cP->
cafile.size())
1163 {sslcafile = strdup(cP->
cafile.c_str());
1164 what2 = (what2 ? "xrd.tlsca to supply 'cadir' and 'cafile'."
1165 : "xrd.tlsca to supply 'cafile'.");
1166 }
1168 crlRefIntervalSec = cP->
crlRT;
1169 what3 = "xrd.tlsca to supply 'refresh' interval.";
1170 }
1174 }
1175
1176
1177
1178 if (!(sslcadir || sslcafile))
1179 {const char *what = Configed();
1180 const char *why = (
httpsspec ?
"a cadir or cafile was not specified!"
1181 : "'xrd.tlsca noverify' was specified!");
1182 if (what)
1183 {
eDest.
Say(
"Config failure: ", what,
" cert verification but ", why);
1184 return 1;
1185 }
1186 }
1188
1189
1190
1191 sslbio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
1192
1193
1194
1195
1196 const char *how = "completed.";
1197 eDest.
Say(
"++++++ HTTPS initialization started.");
1198 if (!InitTLS()) {NoGo = 1; how = "failed.";}
1199 eDest.
Say(
"------ HTTPS initialization ", how);
1200 if (NoGo) return NoGo;
1201
1202
1203
1204 if (LoadExtHandler(extHIVec, ConfigFN, *myEnv)) return 1;
1205
1206
1207
1208 return (InitSecurity() ? NoGo : 1);
1209}
1210
1211
1212
1213
1214
1215const char *XrdHttpProtocol::Configed()
1216{
1217 if (secxtractor &&
gridmap)
return "gridmap and secxtractor require";
1218 if (secxtractor) return "secxtractor requires";
1219 if (
gridmap)
return "gridmap requires";
1220 return 0;
1221}
1222
1223
1224
1225
1226
1228
1230
1231 dest = "";
1232 char save;
1233
1234
1235 if (myBuffEnd >= myBuffStart) {
1236 int l = 0;
1237 for (char *p = myBuffStart; p < myBuffEnd; p++) {
1238 l++;
1239 if (*p == '\n') {
1240 save = *(p+1);
1241 *(p+1) = '\0';
1242 dest.
assign(myBuffStart, 0, l-1);
1243 *(p+1) = save;
1244
1245
1246
1247 BuffConsume(l);
1248
1249
1250 return l;
1251 }
1252
1253 }
1254
1255 return 0;
1256 } else {
1257
1258
1259
1260 int l = 0;
1261 for (
char *p = myBuffStart; p < myBuff->
buff + myBuff->
bsize; p++) {
1262 l++;
1263 if ((*p == '\n') || (*p == '\0')) {
1264 save = *(p+1);
1265 *(p+1) = '\0';
1266 dest.
assign(myBuffStart, 0, l-1);
1267 *(p+1) = save;
1268
1269
1270
1271 BuffConsume(l);
1272
1273
1274 return l;
1275 }
1276
1277 }
1278
1279
1280
1281 l = 0;
1282 for (
char *p = myBuff->
buff; p < myBuffEnd; p++) {
1283 l++;
1284 if ((*p == '\n') || (*p == '\0')) {
1285 save = *(p+1);
1286 *(p+1) = '\0';
1287
1288 int l1 = myBuff->
buff + myBuff->
bsize - myBuffStart;
1289
1290 dest.
assign(myBuffStart, 0, l1-1);
1291
1292 BuffConsume(l1);
1293
1294 dest.
insert(myBuffStart, l1, l-1);
1295
1296
1297 BuffConsume(l);
1298
1299 *(p+1) = save;
1300
1301
1302 return l + l1;
1303 }
1304
1305 }
1306
1307
1308
1309 }
1310
1311 return 0;
1312}
1313
1314
1315
1316
1317
1318int XrdHttpProtocol::getDataOneShot(int blen, bool wait) {
1319 int rlen, maxread;
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333 maxread = std::min(blen, BuffAvailable());
1334 TRACE(
DEBUG,
"getDataOneShot BuffAvailable: " << BuffAvailable() <<
" maxread: " << maxread);
1335
1336 if (!maxread)
1337 return 2;
1338
1339 if (ishttps) {
1340 int sslavail = maxread;
1341
1342 if (!wait) {
1343 int l = SSL_pending(ssl);
1344 if (l > 0)
1345 sslavail = std::min(maxread, SSL_pending(ssl));
1346 }
1347
1348 if (sslavail < 0) {
1350 ERR_print_errors(sslbio_err);
1351 return -1;
1352 }
1353
1354 TRACE(
DEBUG,
"getDataOneShot sslavail: " << sslavail);
1355 if (sslavail <= 0) return 0;
1356
1357 if (myBuffEnd - myBuff->
buff >= myBuff->
bsize) {
1359 myBuffEnd = myBuff->
buff;
1360 }
1361
1362 rlen = SSL_read(ssl, myBuffEnd, sslavail);
1363 if (rlen <= 0) {
1365 ERR_print_errors(sslbio_err);
1366 return -1;
1367 }
1368
1369
1370 } else {
1371
1372 if (myBuffEnd - myBuff->
buff >= myBuff->
bsize) {
1374 myBuffEnd = myBuff->
buff;
1375 }
1376
1377 if (wait)
1379 else
1380 rlen =
Link->
Recv(myBuffEnd, maxread);
1381
1382
1383 if (rlen == 0) {
1385 return -1;
1386 }
1387
1388 if (rlen < 0) {
1390 return -1;
1391 }
1392 }
1393
1394 myBuffEnd += rlen;
1395
1396 TRACE(REQ,
"read " << rlen <<
" of " << blen <<
" bytes");
1397
1398 return 0;
1399}
1400
1402
1403int XrdHttpProtocol::BuffAvailable() {
1404 int r;
1405
1406 if (myBuffEnd >= myBuffStart)
1407 r = myBuff->
buff + myBuff->
bsize - myBuffEnd;
1408 else
1409 r = myBuffStart - myBuffEnd;
1410
1411 if ((r < 0) || (r > myBuff->
bsize)) {
1412 TRACE(REQ,
"internal error, myBuffAvailable: " << r <<
" myBuff->bsize " << myBuff->
bsize);
1413 abort();
1414 }
1415
1416 return r;
1417}
1418
1419
1420
1421
1422
1424
1425int XrdHttpProtocol::BuffUsed() {
1426 int r;
1427
1428 if (myBuffEnd >= myBuffStart)
1429 r = myBuffEnd - myBuffStart;
1430 else
1431
1432 r = myBuff->
bsize - (myBuffStart - myBuffEnd);
1433
1434 if ((r < 0) || (r > myBuff->
bsize)) {
1435 TRACE(REQ,
"internal error, myBuffUsed: " << r <<
" myBuff->bsize " << myBuff->
bsize);
1436 abort();
1437 }
1438
1439 return r;
1440}
1441
1442
1443
1444
1445
1447
1448int XrdHttpProtocol::BuffFree() {
1449 return (myBuff->
bsize - BuffUsed());
1450}
1451
1452
1453
1454
1455
1456void XrdHttpProtocol::BuffConsume(int blen) {
1457
1458 if (blen > myBuff->
bsize) {
1459 TRACE(REQ,
"internal error, BuffConsume(" << blen <<
") smaller than buffsize");
1460 abort();
1461 }
1462
1463 if (blen > BuffUsed()) {
1464 TRACE(REQ,
"internal error, BuffConsume(" << blen <<
") larger than BuffUsed:" << BuffUsed());
1465 abort();
1466 }
1467
1468 myBuffStart = myBuffStart + blen;
1469
1470 if (myBuffStart >= myBuff->
buff + myBuff->
bsize)
1471 myBuffStart -= myBuff->
bsize;
1472
1473 if (myBuffEnd >= myBuff->
buff + myBuff->
bsize)
1474 myBuffEnd -= myBuff->
bsize;
1475
1476 if (BuffUsed() == 0)
1477 myBuffStart = myBuffEnd = myBuff->
buff;
1478}
1479
1480
1481
1482
1483
1492int XrdHttpProtocol::BuffgetData(int blen, char **data, bool wait) {
1493 int rlen;
1494
1495 TRACE(
DEBUG,
"BuffgetData: requested " << blen <<
" bytes");
1496
1497
1498 if (wait) {
1499
1500 if (blen > BuffUsed()) {
1501 TRACE(REQ,
"BuffgetData: need to read " << blen - BuffUsed() <<
" bytes");
1502 if ( getDataOneShot(blen - BuffUsed(), true) )
1503
1504 return 0;
1505 }
1506 } else {
1507
1508 if ( !BuffUsed() ) {
1509 if ( getDataOneShot(blen, false) )
1510
1511 return -1;
1512 }
1513 }
1514
1515
1516
1517 if (myBuffStart <= myBuffEnd) {
1518 rlen = std::min( (long) blen, (long)(myBuffEnd - myBuffStart) );
1519
1520 } else
1521 rlen = std::min( (
long) blen, (
long)(myBuff->
buff + myBuff->
bsize - myBuffStart) );
1522
1523 *data = myBuffStart;
1524 BuffConsume(rlen);
1525 return rlen;
1526}
1527
1528
1529
1530
1531
1533
1534int XrdHttpProtocol::SendData(const char *body, int bodylen) {
1535
1536 int r;
1537
1538 if (body && bodylen) {
1539 TRACE(REQ,
"Sending " << bodylen <<
" bytes");
1540 if (ishttps) {
1541 r = SSL_write(ssl, body, bodylen);
1542 if (r <= 0) {
1543 ERR_print_errors(sslbio_err);
1544 return -1;
1545 }
1546
1547 } else {
1549 if (r <= 0) return -1;
1550 }
1551 }
1552
1553 return 0;
1554}
1555
1556
1557
1558
1559
1560int XrdHttpProtocol::StartSimpleResp(int code, const char *desc, const char *header_to_add, long long bodylen, bool keepalive) {
1561 std::stringstream ss;
1562 const std::string crlf = "\r\n";
1563
1564 ss << "HTTP/1.1 " << code << " ";
1565 if (desc) {
1566 ss << desc;
1567 } else {
1568 if (code == 200) ss << "OK";
1569 else if (code == 100) ss << "Continue";
1570 else if (code == 206) ss << "Partial Content";
1571 else if (code == 302) ss << "Redirect";
1572 else if (code == 307) ss << "Temporary Redirect";
1573 else if (code == 400) ss << "Bad Request";
1574 else if (code == 403) ss << "Forbidden";
1575 else if (code == 404) ss << "Not Found";
1576 else if (code == 405) ss << "Method Not Allowed";
1577 else if (code == 416) ss << "Range Not Satisfiable";
1578 else if (code == 500) ss << "Internal Server Error";
1579 else if (code == 504) ss << "Gateway Timeout";
1580 else ss << "Unknown";
1581 }
1582 ss << crlf;
1583 if (keepalive && (code != 100))
1584 ss << "Connection: Keep-Alive" << crlf;
1585 else
1586 ss << "Connection: Close" << crlf;
1587
1588 ss << "Server: XrootD/" << XrdVSTRING << crlf;
1589
1590 if ((bodylen >= 0) && (code != 100))
1591 ss << "Content-Length: " << bodylen << crlf;
1592
1593 if (header_to_add && (header_to_add[0] != '\0'))
1594 ss << header_to_add << crlf;
1595
1596 ss << crlf;
1597
1598 const std::string &outhdr = ss.str();
1599 TRACEI(RSP,
"Sending resp: " << code <<
" header len:" << outhdr.size());
1600 if (SendData(outhdr.c_str(), outhdr.size()))
1601 return -1;
1602
1603 return 0;
1604}
1605
1606
1607
1608
1609
1610int XrdHttpProtocol::StartChunkedResp(int code, const char *desc, const char *header_to_add, long long bodylen, bool keepalive) {
1611 const std::string crlf = "\r\n";
1612 std::stringstream ss;
1613
1614 if (header_to_add && (header_to_add[0] != '\0')) {
1615 ss << header_to_add << crlf;
1616 }
1617
1618 ss << "Transfer-Encoding: chunked";
1619 TRACEI(RSP,
"Starting chunked response");
1620 return StartSimpleResp(code, desc, ss.str().c_str(), bodylen, keepalive);
1621}
1622
1623
1624
1625
1626
1627int XrdHttpProtocol::ChunkResp(const char *body, long long bodylen) {
1628 long long content_length = (bodylen <= 0) ? (body ? strlen(body) : 0) : bodylen;
1629 if (ChunkRespHeader(content_length))
1630 return -1;
1631
1632 if (body && SendData(body, content_length))
1633 return -1;
1634
1635 return ChunkRespFooter();
1636}
1637
1638
1639
1640
1641
1642int XrdHttpProtocol::ChunkRespHeader(long long bodylen) {
1643 const std::string crlf = "\r\n";
1644 std::stringstream ss;
1645
1646 ss << std::hex << bodylen << std::dec << crlf;
1647
1648 const std::string &chunkhdr = ss.str();
1649 TRACEI(RSP,
"Sending encoded chunk of size " << bodylen);
1650 return (SendData(chunkhdr.c_str(), chunkhdr.size())) ? -1 : 0;
1651}
1652
1653
1654
1655
1656
1657int XrdHttpProtocol::ChunkRespFooter() {
1658 const std::string crlf = "\r\n";
1659 return (SendData(crlf.c_str(), crlf.size())) ? -1 : 0;
1660}
1661
1662
1663
1664
1665
1669
1670int XrdHttpProtocol::SendSimpleResp(int code, const char *desc, const char *header_to_add, const char *body, long long bodylen, bool keepalive) {
1671
1672 long long content_length = bodylen;
1673 if (bodylen <= 0) {
1674 content_length = body ? strlen(body) : 0;
1675 }
1676
1677 if (StartSimpleResp(code, desc, header_to_add, content_length, keepalive) < 0)
1678 return -1;
1679
1680
1681
1682
1683 if (body)
1684 return SendData(body, content_length);
1685
1686 return 0;
1687}
1688
1689
1690
1691
1692
1694
1695
1696
1697
1698
1699
1700
1701
1702 char *rdf;
1703
1704
1705
1708
1712
1714
1715
1716
1718
1719 {
1720 char buf[16];
1721 sprintf(buf,
"%d",
Port);
1723 }
1724
1725
1726
1727 rdf = (parms && *parms ? parms : pi->
ConfigFN);
1728 if (rdf && Config(rdf, pi->
theEnv))
return 0;
1730
1731
1733 if ((rdf = getenv("XRDROLE"))) {
1735
1736 if (!strcasecmp(rdf, "manager") || !strcasecmp(rdf, "supervisor")) {
1738 eDest.
Emsg(
"Config",
"Configured as HTTP(s) redirector.");
1739 } else {
1740
1741 eDest.
Emsg(
"Config",
"Configured as HTTP(s) data server.");
1742 }
1743
1744 } else {
1745 eDest.
Emsg(
"Config",
"No XRDROLE specified.");
1746 }
1747
1748
1749
1753
1754
1755
1756
1757 return 1;
1758}
1759
1760
1761
1762
1764 char *val, keybuf[1024], parmbuf[1024];
1765 char *parm;
1766
1767
1769 if (!val || !val[0]) {
1770 err.
Emsg(
"Config",
"No headerkey specified.");
1771 return 1;
1772 } else {
1773
1774
1775 while ( *val && !isalnum(*val) ) val++;
1776 strcpy(keybuf, val);
1777
1778
1779 char *pp;
1780 pp = keybuf + strlen(keybuf) - 1;
1781 while ( (pp >= keybuf) && (!isalnum(*pp)) ) {
1782 *pp = '\0';
1783 pp--;
1784 }
1785
1787
1788
1789 if(!parm || !parm[0]) {
1790 err.
Emsg(
"Config",
"No header2cgi value specified. key: '", keybuf,
"'");
1791 return 1;
1792 }
1793
1794
1795 while ( *parm && !isalnum(*parm) ) parm++;
1796 strcpy(parmbuf, parm);
1797
1798
1799 pp = parmbuf + strlen(parmbuf) - 1;
1800 while ( (pp >= parmbuf) && (!isalnum(*pp)) ) {
1801 *pp = '\0';
1802 pp--;
1803 }
1804
1805
1806 try {
1807 header2cgi[keybuf] = parmbuf;
1808 } catch ( ... ) {
1809 err.
Emsg(
"Config",
"Can't insert new header2cgi rule. key: '", keybuf,
"'");
1810 return 1;
1811 }
1812
1813 }
1814 return 0;
1815}
1816
1817
1818
1819
1820
1821
1822bool XrdHttpProtocol::InitTLS() {
1823
1827
1828
1829
1832
1835
1836
1837
1840 return false;
1841 }
1842
1843
1844
1845
1846
1847 static const char *sess_ctx_id = "XrdHTTPSessionCtx";
1848 unsigned int n =(unsigned int)(strlen(sess_ctx_id)+1);
1850
1851
1852
1854 {
eDest.
Say(
"Config failure: ",
"Unable to set allowable https ciphers!");
1855 return false;
1856 }
1857
1858
1859
1860 return true;
1861}
1862
1863
1864
1865
1866
1867void XrdHttpProtocol::Cleanup() {
1868
1869 TRACE(ALL,
" Cleanup");
1870
1871 if (
BPool && myBuff) {
1872 BuffConsume(BuffUsed());
1874 myBuff = 0;
1875 }
1876
1877 if (ssl) {
1878
1879
1880
1881
1882
1883
1884
1885
1886 int ret = SSL_shutdown(ssl);
1887 if (ret != 1) {
1888 if(ret == 0) {
1889
1890 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1891 ERR_remove_thread_state(nullptr);
1892 #endif
1893 } else {
1894
1895 TRACE(ALL,
" SSL_shutdown failed");
1896 ERR_print_errors(sslbio_err);
1897 }
1898 }
1899
1900 if (secxtractor)
1902
1903 SSL_free(ssl);
1904
1905 }
1906
1907
1908 ssl = 0;
1909 sbio = 0;
1910
1919
1921
1924}
1925
1926
1927
1928
1929
1930void XrdHttpProtocol::Reset() {
1931
1932 TRACE(ALL,
" Reset");
1936
1937 if (myBuff) {
1939 myBuff = 0;
1940 }
1941 myBuffStart = myBuffEnd = 0;
1942
1943 DoingLogin = false;
1944 DoneSetInfo = false;
1945
1946 ResumeBytes = 0;
1947 Resume = 0;
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1964 ishttps = false;
1965 ssldone = false;
1966
1968 ssl = 0;
1969 sbio = 0;
1970
1971}
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988int XrdHttpProtocol::xhttpsmode(
XrdOucStream & Config) {
1989 char *val;
1990
1991
1992
1994 if (!val || !val[0]) {
1995 eDest.
Emsg(
"Config",
"httpsmode parameter not specified");
1996 return 1;
1997 }
1998
1999
2000
2004 else {
eDest.
Emsg(
"Config",
"invalid httpsmode parameter - ", val);
2005 return 1;
2006 }
2007 return 0;
2008}
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023int XrdHttpProtocol::xsslverifydepth(
XrdOucStream & Config) {
2024 char *val;
2025
2026
2027
2029 if (!val || !val[0]) {
2030 eDest.
Emsg(
"Config",
"sslverifydepth value not specified");
2031 return 1;
2032 }
2033
2034
2035
2037
2039 return 0;
2040}
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2056 char *val;
2057
2058
2059
2061 if (!val || !val[0]) {
2062 eDest.
Emsg(
"Config",
"HTTP X509 certificate not specified");
2063 return 1;
2064 }
2065
2066
2067
2070
2071
2072
2074 return 0;
2075}
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2091 char *val;
2092
2093
2094
2096 if (!val || !val[0]) {
2097 eDest.
Emsg(
"Config",
"HTTP X509 key not specified");
2098 return 1;
2099 }
2100
2101
2102
2105
2107 return 0;
2108}
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2128 char *val;
2129
2130
2131
2133 if (!val || !val[0]) {
2134 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file location not specified");
2135 return 1;
2136 }
2137
2138
2139
2140 if (!strncmp(val, "required", 8)) {
2143
2144 if (!val || !val[0]) {
2145 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file missing after [required] "
2146 "parameter");
2147 return 1;
2148 }
2149 }
2150
2151
2152
2153 if (!strcmp(val, "compatNameGeneration")) {
2156 if (!val || !val[0]) {
2157 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file missing after "
2158 "[compatNameGeneration] parameter");
2159 return 1;
2160 }
2161 }
2162
2163
2164
2165
2168 return 0;
2169}
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184int XrdHttpProtocol::xsslcafile(
XrdOucStream & Config) {
2185 char *val;
2186
2187
2188
2190 if (!val || !val[0]) {
2191 eDest.
Emsg(
"Config",
"HTTP X509 CAfile not specified");
2192 return 1;
2193 }
2194
2195
2196
2199
2201 return 0;
2202}
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217int XrdHttpProtocol::xsecretkey(
XrdOucStream & Config) {
2218 char *val;
2219 bool inFile = false;
2220
2221
2222
2224 if (!val || !val[0]) {
2225 eDest.
Emsg(
"Config",
"Shared secret key not specified");
2226 return 1;
2227 }
2228
2229
2230
2231
2232
2233 if (val[0] == '/') {
2235 inFile = true;
2236 if (
stat(val, &st) ) {
2237 eDest.
Emsg(
"Config", errno,
"stat shared secret key file", val);
2238 return 1;
2239 }
2240
2241 if ( st.st_mode & S_IWOTH & S_IWGRP & S_IROTH) {
2242 eDest.
Emsg(
"Config",
"For your own security, the shared secret key file cannot be world readable or group writable'", val,
"'");
2243 return 1;
2244 }
2245
2246 FILE *fp =
fopen(val,
"r");
2247
2248 if( fp == NULL ) {
2249 eDest.
Emsg(
"Config", errno,
"open shared secret key file", val);
2250 return 1;
2251 }
2252
2253 char line[1024];
2254 while( fgets(line, 1024, fp) ) {
2255 char *pp;
2256
2257
2258 pp = line + strlen(line) - 1;
2259 while ( (pp >= line) && (!isalnum(*pp)) ) {
2260 *pp = '\0';
2261 pp--;
2262 }
2263
2264
2265 pp = line;
2266 while ( *pp && !isalnum(*pp) ) pp++;
2267
2268 if ( strlen(pp) >= 32 ) {
2269 eDest.
Say(
"Config",
"Secret key loaded.");
2270
2273
2275 return 0;
2276 }
2277
2278 }
2279
2281 eDest.
Emsg(
"Config",
"Cannot find useful secretkey in file '", val,
"'");
2282 return 1;
2283
2284 }
2285
2286 if ( strlen(val) < 32 ) {
2287 eDest.
Emsg(
"Config",
"Secret key is too short");
2288 return 1;
2289 }
2290
2291
2294 if (!inFile)
Config.noEcho();
2295
2296 return 0;
2297}
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2313 char *val;
2314
2315
2316
2318 if (!val || !val[0]) {
2319 eDest.
Emsg(
"Config",
"listingdeny flag not specified");
2320 return 1;
2321 }
2322
2323
2324
2325 listdeny = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2326
2327
2328 return 0;
2329}
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344int XrdHttpProtocol::xlistredir(
XrdOucStream & Config) {
2345 char *val;
2346
2347
2348
2350 if (!val || !val[0]) {
2351 eDest.
Emsg(
"Config",
"listingredir flag not specified");
2352 return 1;
2353 }
2354
2355
2356
2359
2360
2361 return 0;
2362}
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377int XrdHttpProtocol::xdesthttps(
XrdOucStream & Config) {
2378 char *val;
2379
2380
2381
2383 if (!val || !val[0]) {
2384 eDest.
Emsg(
"Config",
"desthttps flag not specified");
2385 return 1;
2386 }
2387
2388
2389
2390 isdesthttps = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2391
2392
2393 return 0;
2394}
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409int XrdHttpProtocol::xembeddedstatic(
XrdOucStream & Config) {
2410 char *val;
2411
2412
2413
2415 if (!val || !val[0]) {
2416 eDest.
Emsg(
"Config",
"embeddedstatic flag not specified");
2417 return 1;
2418 }
2419
2420
2421
2422 embeddedstatic = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2423
2424
2425 return 0;
2426}
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441int XrdHttpProtocol::xstaticredir(
XrdOucStream & Config) {
2442 char *val;
2443
2444
2445
2447 if (!val || !val[0]) {
2448 eDest.
Emsg(
"Config",
"staticredir url not specified");
2449 return 1;
2450 }
2451
2452
2453
2456
2457 return 0;
2458}
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476int XrdHttpProtocol::xstaticpreload(
XrdOucStream & Config) {
2477 char *val, *k, key[1024];
2478
2479
2480
2482 if (!k || !k[0]) {
2483 eDest.
Emsg(
"Config",
"preloadstatic urlpath not specified");
2484 return 1;
2485 }
2486
2487 strcpy(key, k);
2488
2489
2490
2492 if (!val || !val[0]) {
2493 eDest.
Emsg(
"Config",
"preloadstatic filename not specified");
2494 return 1;
2495 }
2496
2497
2498 int fp =
open(val, O_RDONLY);
2499 if( fp < 0 ) {
2500 eDest.
Emsg(
"Config", errno,
"open preloadstatic filename", val);
2501 return 1;
2502 }
2503
2504 StaticPreloadInfo *nfo = new StaticPreloadInfo;
2505
2506 nfo->data = (char *)malloc(65536);
2507 nfo->len =
read(fp, (
void *)nfo->data, 65536);
2509
2510 if (nfo->len <= 0) {
2511 eDest.
Emsg(
"Config", errno,
"read from preloadstatic filename", val);
2512 return 1;
2513 }
2514
2515 if (nfo->len >= 65536) {
2516 eDest.
Emsg(
"Config",
"Truncated preloadstatic filename. Max is 64 KB '", val,
"'");
2517 return 1;
2518 }
2519
2520
2521
2524
2526 return 0;
2527}
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542int XrdHttpProtocol::xselfhttps2http(
XrdOucStream & Config) {
2543 char *val;
2544
2545
2546
2548 if (!val || !val[0]) {
2549 eDest.
Emsg(
"Config",
"selfhttps2http flag not specified");
2550 return 1;
2551 }
2552
2553
2554
2555 selfhttps2http = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2556
2557
2558 return 0;
2559}
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577int XrdHttpProtocol::xsecxtractor(
XrdOucStream& Config) {
2578 char *val;
2579
2580
2581
2583 if (!val || !val[0]) {
2584 eDest.
Emsg(
"Config",
"No security extractor plugin specified.");
2585 return 1;
2586 } else {
2587
2588
2589 if (!strncmp(val, "required", 8)) {
2590 isRequiredXtractor = true;
2592
2593 if (!val || !val[0]) {
2594 eDest.
Emsg(
"Config",
"No security extractor plugin after [required] "
2595 "parameter");
2596 return 1;
2597 }
2598 }
2599
2600 char libName[4096];
2601 strlcpy(libName, val,
sizeof(libName));
2602 libName[sizeof(libName) - 1] = '\0';
2603 char libParms[4096];
2604
2605 if (!
Config.GetRest(libParms, 4095)) {
2606 eDest.
Emsg(
"Config",
"secxtractor config params longer than 4k");
2607 return 1;
2608 }
2609
2610
2611
2612 if (LoadSecXtractor(&
eDest, libName, libParms)) {
2613 return 1;
2614 }
2615 }
2616
2617 return 0;
2618}
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2638 std::vector<extHInfo> &hiVec) {
2639 char *val, path[1024], namebuf[1024];
2640 char *parm;
2641
2642 bool noTlsOK = false;
2643
2644
2645
2647 if (!val || !val[0]) {
2648 eDest.
Emsg(
"Config",
"No instance name specified for an http external handler plugin.");
2649 return 1;
2650 }
2651 if (strlen(val) >= 16) {
2652 eDest.
Emsg(
"Config",
"Instance name too long for an http external handler plugin.");
2653 return 1;
2654 }
2655 strncpy(namebuf, val, sizeof(namebuf));
2656 namebuf[ sizeof(namebuf)-1 ] = '\0';
2657
2658
2660
2661 if(val && !strcmp("+notls",val)) {
2662 noTlsOK = true;
2664 }
2665
2666
2667
2668 if (!val || !val[0]) {
2669 eDest.
Emsg(
"Config",
"No http external handler plugin specified.");
2670 return 1;
2671 }
2672 if (strlen(val) >= (int)sizeof(path)) {
2673 eDest.
Emsg(
"Config",
"Path too long for an http external handler plugin.");
2674 return 1;
2675 }
2676
2677 strcpy(path, val);
2678
2679
2680
2682
2683
2684
2685 for (int i = 0; i < (int)hiVec.size(); i++)
2686 {if (hiVec[i].extHName == namebuf) {
2687 eDest.
Emsg(
"Config",
"Instance name already present for "
2688 "http external handler plugin",
2689 hiVec[i].extHPath.c_str());
2690 return 1;
2691 }
2692 }
2693
2694
2695
2697 eDest.
Emsg(
"Config",
"Cannot load one more exthandler. Max is 4");
2698 return 1;
2699 }
2700
2701
2702
2703 hiVec.push_back(extHInfo(namebuf, path, (parm ? parm : ""), noTlsOK));
2704
2705 return 0;
2706}
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724int XrdHttpProtocol::xheader2cgi(
XrdOucStream & Config) {
2726}
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2742 char *val;
2743
2744
2745
2747 if (!val || !val[0]) {
2748 eDest.
Emsg(
"Config",
"HTTP X509 CAdir not specified");
2749 return 1;
2750 }
2751
2752
2753
2756
2758 return 0;
2759}
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775int XrdHttpProtocol::xsslcipherfilter(
XrdOucStream & Config) {
2776 char *val;
2777
2778
2779
2781 if (!val || !val[0]) {
2782 eDest.
Emsg(
"Config",
"SSL cipherlist filter string not specified");
2783 return 1;
2784 }
2785
2786
2787
2790
2791 return 0;
2792}
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2806
2807 char *val;
2808
2809
2810
2812 if (!val || !val[0])
2813 {
eDest.
Emsg(
"Config",
"tlsreuse argument not specified");
return 1;}
2814
2815
2816
2817 if (!strcmp(val, "off"))
2819 return 0;
2820 }
2821
2822
2823
2824 if (!strcmp(val, "on"))
2826 return 0;
2827 }
2828
2829
2830
2831 eDest.
Emsg(
"config",
"invalid tlsreuse parameter -", val);
2832 return 1;
2833}
2834
2836 char *val =
Config.GetWord();
2837 if(val) {
2838 if(!strcmp("tpc",val)) {
2839 if(!(val =
Config.GetWord())) {
2840 eDest.
Emsg(
"Config",
"http.auth tpc value not specified.");
return 1;
2841 } else {
2842 if(!strcmp("fcreds",val)) {
2844 } else {
2845 eDest.
Emsg(
"Config",
"http.auth tpc value is invalid");
return 1;
2846 }
2847 }
2848 } else {
2849 eDest.
Emsg(
"Config",
"http.auth value is invalid");
return 1;
2850 }
2851 }
2852 return 0;
2853}
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2870
2871 char *val;
2872
2873 static struct traceopts {
2874 const char *opname;
2875 int opval;
2876 } tropts[] = {
2884 };
2885 int i, neg, trval = 0, numopts = sizeof (tropts) / sizeof (struct traceopts);
2886
2887 if (!(val =
Config.GetWord())) {
2888 eDest.
Emsg(
"config",
"trace option not specified");
2889 return 1;
2890 }
2891 while (val) {
2892 if (!strcmp(val, "off")) trval = 0;
2893 else {
2894 if ((neg = (val[0] == '-' && val[1]))) val++;
2895 for (i = 0; i < numopts; i++) {
2896 if (!strcmp(val, tropts[i].opname)) {
2897 if (neg) trval &= ~tropts[i].opval;
2898 else trval |= tropts[i].opval;
2899 break;
2900 }
2901 }
2902 if (i >= numopts)
2903 eDest.
Emsg(
"config",
"invalid trace option", val);
2904 }
2906 }
2908 return 0;
2909}
2910
2912 int l;
2913 bool b;
2917
2922 l = strlen(fname) + 1;
2924
2927 if (!b) {
2928 return -1;
2929 }
2930
2931
2932 return 0;
2933}
2934
2935
2936
2937
2938
2940 size_t length;
2947 length = fname.
length() + 1;
2949
2951
2953}
2954
2955
2956static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION);
2957
2958
2959int XrdHttpProtocol::LoadSecXtractor(
XrdSysError *myeDest,
const char *libName,
2960 const char *libParms) {
2961
2962
2963
2964 if (secxtractor) return 1;
2965
2966 XrdOucPinLoader myLib(myeDest, &compiledVer,
"secxtractorlib", libName);
2968
2969
2970
2972 if (ep && (secxtractor = ep(myeDest, NULL, libParms))) return 0;
2973 myLib.Unload();
2974 return 1;
2975}
2976
2977
2978
2979
2980int XrdHttpProtocol::LoadExtHandlerNoTls(std::vector<extHInfo> &hiVec,
const char *cFN,
XrdOucEnv &myEnv) {
2981 for (int i = 0; i < (int) hiVec.size(); i++) {
2982 if(hiVec[i].extHNoTlsOK) {
2983
2984 if (LoadExtHandler(&
eDest, hiVec[i].extHPath.c_str(), cFN,
2985 hiVec[i].extHParm.c_str(), &myEnv,
2986 hiVec[i].extHName.c_str()))
2987 return 1;
2988 }
2989 }
2990 return 0;
2991}
2992
2993int XrdHttpProtocol::LoadExtHandler(std::vector<extHInfo> &hiVec,
2995
2996
2997
3002
3003
3004
3005 for (int i = 0; i < (int)hiVec.size(); i++) {
3006
3007
3008 if(!ExtHandlerLoaded(hiVec[i].extHName.c_str())) {
3009 if (LoadExtHandler(&
eDest, hiVec[i].extHPath.c_str(), cFN,
3010 hiVec[i].extHParm.c_str(), &myEnv,
3011 hiVec[i].extHName.c_str())) return 1;
3012 }
3013 }
3014 return 0;
3015}
3016
3017
3018int XrdHttpProtocol::LoadExtHandler(
XrdSysError *myeDest,
const char *libName,
3019 const char *configFN, const char *libParms,
3020 XrdOucEnv *myEnv,
const char *instName) {
3021
3022
3023
3024 if (ExtHandlerLoaded(instName)) {
3025 eDest.
Emsg(
"Config",
"Instance name already present for an http external handler plugin.");
3026 return 1;
3027 }
3029 eDest.
Emsg(
"Config",
"Cannot load one more exthandler. Max is 4");
3030 return 1;
3031 }
3032
3033 XrdOucPinLoader myLib(myeDest, &compiledVer,
"exthandlerlib", libName);
3035
3036
3037
3039
3041 if (ep && (newhandler = ep(myeDest, configFN, libParms, myEnv))) {
3042
3043
3044 strncpy( exthandler[exthandlercnt].name, instName, 16 );
3045 exthandler[exthandlercnt].name[15] = '\0';
3046 exthandler[exthandlercnt++].ptr = newhandler;
3047
3048 return 0;
3049 }
3050
3051 myLib.Unload();
3052 return 1;
3053}
3054
3055
3056
3057
3058
3059bool XrdHttpProtocol::ExtHandlerLoaded(const char *handlername) {
3060 for (int i = 0; i < exthandlercnt; i++) {
3061 if ( !strncmp(exthandler[i].name, handlername, 15) ) {
3062 return true;
3063 }
3064 }
3065 return false;
3066}
3067
3068
3069
3071
3072 for (int i = 0; i < exthandlercnt; i++) {
3074 return exthandler[i].ptr;
3075 }
3076 }
3077 return NULL;
3078}
struct ClientQueryRequest query
struct ClientStatRequest stat
#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)
XrdSysTrace XrdHttpTrace("http")
static int BIO_XrdLink_read(BIO *bio, char *data, size_t datal, size_t *read)
static int BIO_XrdLink_destroy(BIO *bio)
static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION)
#define MAX_XRDHTTPEXTHANDLERS
#define XrdHttpSecXtractorArgs
#define TLS_SET_VDEPTH(cOpts, vdv)
#define TLS_SET_REFINT(cOpts, refi)
void Release(XrdBuffer *bp)
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 * Port_str
Our port, as a string.
XrdXrootd::Bridge * Bridge
The Bridge that we use to exercise the xrootd internals.
static char * staticredir
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.
int doStat(char *fname)
Perform a Stat request.
static int readWait
Timeout for reading data.
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 XrdBuffManager * BPool
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.
ClientRequest xrdreq
The last issued xrd request, often pending.
virtual int FreeSSL(SSL *)
int setEtext(const char *text)
int Recv(char *buff, int blen)
int Send(const char *buff, int blen)
void Set(int inQMax, time_t agemax=1800)
static bool Import(const char *var, char *&val)
void Put(const char *varname, const char *value)
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)
const char * c_str() const
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
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.