XRootD
Loading...
Searching...
No Matches
XrdHttpTpcConfigure.cc
Go to the documentation of this file.
1
2#include "XrdHttpTpcTPC.hh"
3
4#include <climits>
5#include <dlfcn.h>
6#include <fcntl.h>
7
8#include "XrdOuc/XrdOuca2x.hh"
9#include "XrdOuc/XrdOucEnv.hh"
15
16using namespace TPC;
17
18
19bool TPCHandler::Configure(const char *configfn, XrdOucEnv *myEnv)
20{
21 XrdOucEnv cfgEnv;
22 XrdOucStream Config(&m_log, getenv("XRDINSTANCE"), &cfgEnv, "=====> ");
23
24 m_log.setMsgMask(LogMask::Warning | LogMask::Error);
25
26 // test if XrdEC is used
27 usingEC = getenv("XRDCL_EC")? true : false;
28 // Test if the CRL checking is enabled
29 allowMissingCRL = (bool) myEnv->GetInt("http.allowmissingcrl");
30 std::string authLib;
31 std::string authLibParms;
32 int cfgFD = open(configfn, O_RDONLY, 0);
33 if (cfgFD < 0) {
34 m_log.Emsg("Config", errno, "open config file", configfn);
35 return false;
36 }
37 Config.Attach(cfgFD);
38 static const char *cvec[] = { "*** http tpc plugin config:", 0 };
39 Config.Capture(cvec);
40 const char *val;
41 while ((val = Config.GetMyFirstWord())) {
42 if (!strcmp("http.desthttps", val)) {
43 if (!(val = Config.GetWord())) {
44 Config.Close();
45 m_log.Emsg("Config", "http.desthttps value not specified");
46 return false;
47 }
48 if (!strcmp("1", val) || !strcasecmp("yes", val) || !strcasecmp("true", val)) {
49 m_desthttps = true;
50 } else if (!strcmp("0", val) || !strcasecmp("no", val) || !strcasecmp("false", val)) {
51 m_desthttps = false;
52 } else {
53 Config.Close();
54 m_log.Emsg("Config", "https.desthttps value is invalid", val);
55 return false;
56 }
57 } else if (!strcmp("tpc.allow", val)) {
58 if (!(val = Config.GetWord())) {
59 Config.Close();
60 m_log.Emsg("Config", "tpc.allow value not specified");
61 return false;
62 }
63 if (strcmp(val, "local") == 0) {
64 m_allow_local = true;
65 } else if (strcmp(val, "private") == 0) {
66 m_allow_private = true;
67 } else {
68 Config.Close();
69 m_log.Emsg("Config", "tpc.allow value is invalid", val);
70 return false;
71 }
72 } else if (!strcmp("tpc.deny", val)) {
73 if (!(val = Config.GetWord())) {
74 Config.Close();
75 m_log.Emsg("Config", "tpc.deny value not specified");
76 return false;
77 }
78 if (strcmp(val, "local") == 0) {
79 m_allow_local = false;
80 } else if (strcmp(val, "private") == 0) {
81 m_allow_private = false;
82 } else {
83 Config.Close();
84 m_log.Emsg("Config", "tpc.deny value is invalid", val);
85 return false;
86 }
87 } else if (!strcmp("tpc.trace", val)) {
88 if (!ConfigureLogger(Config)) {
89 Config.Close();
90 return false;
91 }
92 } else if (!strcmp("tpc.fixed_route", val)) {
93 if (!(val = Config.GetWord())) {
94 Config.Close();
95 m_log.Emsg("Config", "tpc.fixed_route value not specified");
96 return false;
97 }
98 if (!strcmp("1", val) || !strcasecmp("yes", val) || !strcasecmp("true", val)) {
99 m_fixed_route= true;
100 } else if (!strcmp("0", val) || !strcasecmp("no", val) || !strcasecmp("false", val)) {
101 m_fixed_route= false;
102 } else {
103 Config.Close();
104 m_log.Emsg("Config", "tpc.fixed_route value is invalid", val);
105 return false;
106 }
107 } else if (!strcmp("tpc.header2cgi",val)) {
108 // header2cgi parsing
109 if(XrdHttpProtocol::parseHeader2CGI(Config,m_log,hdr2cgimap)){
110 Config.Close();
111 return false;
112 }
113 // remove authorization header2cgi parsing as it will anyway be added to the CGI before the file open
114 // by the HTTP/TPC logic
115 auto authHdr = XrdOucTUtils::caseInsensitiveFind(hdr2cgimap,"authorization");
116 if(authHdr != hdr2cgimap.end()) {
117 hdr2cgimap.erase(authHdr);
118 }
119 } else if (!strcmp("tpc.low_speed", val)) {
120 if (!(val = Config.GetWord())) {
121 Config.Close();
122 m_log.Emsg("Config", "tpc.low_speed rate not specified.");
123 return false;
124 }
125
126 long long low_speed_limit;
127 if (XrdOuca2x::a2sz(m_log, "low speed rate", val, &low_speed_limit, 0, LONG_MAX)) {
128 return false;
129 }
130 m_low_speed_limit = static_cast<long>(low_speed_limit);
131
132 if ((val = Config.GetWord())) {
133 int low_speed_time;
134 if (XrdOuca2x::a2tm(m_log, "low speed time", val, &low_speed_time, 1)) {
135 return false;
136 }
137 m_low_speed_time = low_speed_time;
138 }
139 } else if (!strcmp("tpc.timeout", val)) {
140 if (!(val = Config.GetWord())) {
141 Config.Close();
142 m_log.Emsg("Config","tpc.timeout value not specified."); return false;
143 }
144 if (XrdOuca2x::a2tm(m_log, "timeout value", val, &m_timeout, 0)) return false;
145 // First byte timeout can be set separately from the continuous timeout.
146 if ((val = Config.GetWord())) {
147 if (XrdOuca2x::a2tm(m_log, "first byte timeout value", val, &m_first_timeout, 0)) return false;
148 } else {
149 m_first_timeout = 2*m_timeout;
150 }
151 }
152 }
153 Config.Close();
154
155 // Internal override: allow xrdtpc to use a different ca dir from the one prepared by the xrootd
156 // framework. meant for exceptional situations where the site might need a specially-prepared set
157 // of cas only for tpc (such as trying out various workarounds for libnss). Explicitly disables
158 // the NSS hack below.
159 auto env_cadir = getenv("XRDTPC_CADIR");
160 if (env_cadir) m_cadir = env_cadir;
161
162 // Sharing a single pre-parsed CA/CRL store between transfers relies on
163 // CURLOPT_SSL_CTX_FUNCTION, which only libcurl's OpenSSL, mbedTLS and wolfSSL
164 // backends implement; the others reject it with CURLE_NOT_BUILT_IN. libcurl
165 // checks this against the backend selected at run time rather than at build
166 // time, so probe an actual handle, and do it here so that an unsupported build
167 // is reported at startup instead of silently costing memory per transfer.
168 {
169 ManagedCurlHandle probe(curl_easy_init());
170 m_sslctx_supported = probe &&
171 curl_easy_setopt(probe.get(), CURLOPT_SSL_CTX_FUNCTION,
172 ssl_ctx_callback) == CURLE_OK;
173 if (!m_sslctx_supported) {
174 m_log.Emsg("Config", "libcurl does not support CURLOPT_SSL_CTX_FUNCTION; "
175 "each transfer will parse the CA and CRL bundles for itself, "
176 "which costs significant memory per concurrent transfer.");
177 }
178 }
179
180 const char *cadir = nullptr, *cafile = nullptr;
181 if ((cadir = env_cadir ? env_cadir : myEnv->Get("http.cadir"))) {
182 m_cadir = cadir;
183 if (!env_cadir) {
184 // Only ask for the pre-parsed store when we can actually install it;
185 // maintaining one costs tens of MB that the fallback path never reads.
186 m_ca_file.reset(new XrdTlsTempCA(&m_log, m_cadir, m_sslctx_supported));
187 if (!m_ca_file->IsValid()) {
188 m_log.Emsg("Config", "CAs / CRL generation for libcurl failed.");
189 return false;
190 }
191 }
192 }
193 if ((cafile = myEnv->Get("http.cafile"))) {
194 m_cafile = cafile;
195 }
196
197 if (!cadir && !cafile) {
198 // We do not necessary need TLS to perform HTTP TPC transfers, just log that these values were not specified
199 m_log.Emsg("Config", "neither xrd.tls cadir nor certfile value specified; is TLS enabled?");
200 }
201
202 void *sfs_raw_ptr;
203 if ((sfs_raw_ptr = myEnv->GetPtr("XrdSfsFileSystem*"))) {
204 m_sfs = static_cast<XrdSfsFileSystem*>(sfs_raw_ptr);
205 m_log.Emsg("Config", "Using filesystem object from the framework.");
206 return true;
207 } else {
208 m_log.Emsg("Config", "No filesystem object available to HTTP-TPC subsystem. Internal error.");
209 return false;
210 }
211 return true;
212}
213
214bool TPCHandler::ConfigureLogger(XrdOucStream &config_obj)
215{
216 char *val = config_obj.GetWord();
217 if (!val || !val[0])
218 {
219 m_log.Emsg("Config", "tpc.trace requires at least one directive [all | error | warning | info | debug | none]");
220 return false;
221 }
222 // If the config option is given, reset the log mask.
223 m_log.setMsgMask(0);
224
225 do {
226 if (!strcasecmp(val, "all"))
227 {
228 m_log.setMsgMask(m_log.getMsgMask() | LogMask::All);
229 }
230 else if (!strcasecmp(val, "error"))
231 {
232 m_log.setMsgMask(m_log.getMsgMask() | LogMask::Error);
233 }
234 else if (!strcasecmp(val, "warning"))
235 {
236 m_log.setMsgMask(m_log.getMsgMask() | LogMask::Warning);
237 }
238 else if (!strcasecmp(val, "info"))
239 {
240 m_log.setMsgMask(m_log.getMsgMask() | LogMask::Info);
241 }
242 else if (!strcasecmp(val, "debug"))
243 {
244 m_log.setMsgMask(m_log.getMsgMask() | LogMask::Debug);
245 }
246 else if (!strcasecmp(val, "none"))
247 {
248 m_log.setMsgMask(0);
249 }
250 else
251 {
252 m_log.Emsg("Config", "tpc.trace encountered an unknown directive (valid values: [all | error | warning | info | debug | none]):", val);
253 return false;
254 }
255 val = config_obj.GetWord();
256 } while (val);
257
258 return true;
259}
A pragmatic implementation of the HTTP/DAV protocol for the Xrd framework.
#define open
Definition XrdPosix.hh:76
static int parseHeader2CGI(XrdOucStream &Config, XrdSysError &err, std::map< std::string, std::string > &header2cgi)
Use this function to parse header2cgi configurations.
long GetInt(const char *varname)
Definition XrdOucEnv.cc:253
char * Get(const char *varname)
Definition XrdOucEnv.hh:69
void * GetPtr(const char *varname)
Definition XrdOucEnv.cc:281
char * GetWord(int lowcase=0)
static std::map< std::string, T >::const_iterator caseInsensitiveFind(const std::map< std::string, T > &m, const std::string &lowerCaseSearchKey)
static int a2sz(XrdSysError &, const char *emsg, const char *item, long long *val, long long minv=-1, long long maxv=-1)
Definition XrdOuca2x.cc:257
static int a2tm(XrdSysError &, const char *emsg, const char *item, int *val, int minv=-1, int maxv=-1)
Definition XrdOuca2x.cc:288
std::unique_ptr< CURL, CurlDeleter > ManagedCurlHandle
XrdCmsConfig Config