Back to index

nordugrid-arc-nox  1.1.0~rc6
ClientInterface.cpp
Go to the documentation of this file.
00001 // -*- indent-tabs-mode: nil -*-
00002 
00003 #ifdef HAVE_CONFIG_H
00004 #include <config.h>
00005 #endif
00006 
00007 // This define is needed to have maximal values for types with fixed size
00008 #define __STDC_LIMIT_MACROS
00009 #include <stdlib.h>
00010 #include <map>
00011 
00012 #include <arc/StringConv.h>
00013 #include <arc/message/MCCLoader.h>
00014 #include <arc/Utils.h>
00015 
00016 #include "ClientInterface.h"
00017 
00018 namespace Arc {
00019 
00020   Logger ClientInterface::logger(Logger::getRootLogger(), "ClientInterface");
00021 
00022   static void xml_add_element(XMLNode xml, XMLNode element) {
00023     if ((std::string)(element.Attribute("overlay")) != "add")
00024       if (element.Size() > 0) {
00025         std::string element_name = element.Name(); // FullName ?
00026         std::string element_id = (std::string)(element.Attribute("name"));
00027         for (XMLNode x = xml[element_name]; (bool)x; x = x[1]) {
00028           if (!element_id.empty())
00029             if (element_id != (std::string)(x.Attribute("name")))
00030               continue;
00031           for (int n = 0;; ++n) {
00032             XMLNode e = element.Child(n);
00033             if (!e)
00034               break;
00035             xml_add_element(x, e);
00036           }
00037         }
00038         return;
00039       }
00040     xml.NewChild(element, 0);
00041     return;
00042   }
00043 
00044   static void xml_add_elements(XMLNode xml, XMLNode elements) {
00045     for (int n = 0;; ++n) {
00046       XMLNode e = elements.Child(n);
00047       if (!e)
00048         break;
00049       xml_add_element(xml, e);
00050     }
00051   }
00052 
00053   static XMLNode ConfigMakeComponent(XMLNode chain, const char *name,
00054                                      const char *id, const char *next = NULL) {
00055     XMLNode comp = chain.NewChild("Component");
00056 
00057     // Make sure namespaces and names are correct
00058     comp.NewAttribute("name") = name;
00059     comp.NewAttribute("id") = id;
00060     if (next)
00061       comp.NewChild("next").NewAttribute("id") = next;
00062     return comp;
00063   }
00064 
00065   static XMLNode ConfigFindComponent(XMLNode chain, const char *name,
00066                                      const char *id) {
00067     XMLNode comp = chain["Component"];
00068     for (; (bool)comp; ++comp)
00069       if ((comp.Attribute("name") == name) &&
00070           (comp.Attribute("id") == id))
00071         return comp;
00072   }
00073 
00074   ClientInterface::ClientInterface(const BaseConfig& cfg)
00075     : xmlcfg(NS()),
00076       //Need to add all of the configuration namespaces here?
00077       loader() {
00078     cfg.MakeConfig(xmlcfg);
00079     xmlcfg.NewChild("Chain");
00080     cfg.overlay.New(overlay);
00081   }
00082 
00083   ClientInterface::~ClientInterface() {
00084     if (loader)
00085       delete loader;
00086   }
00087 
00088   bool ClientInterface::Load() {
00089     if (!loader) {
00090       if (overlay)
00091         Overlay(overlay);
00092       loader = new MCCLoader(xmlcfg);
00093     }
00094     return (*loader);
00095   }
00096 
00097   void ClientInterface::Overlay(XMLNode cfg) {
00098     xml_add_elements(xmlcfg, cfg);
00099   }
00100 
00101   void ClientInterface::AddSecHandler(XMLNode mcccfg, XMLNode handlercfg) {
00102     // Insert SecHandler configuration into MCC configuration block
00103     // Make sure namespaces and names are correct
00104     mcccfg.NewChild(handlercfg).Name("SecHandler");
00105   }
00106 
00107   void ClientInterface::AddPlugin(XMLNode mcccfg, const std::string& libname, const std::string& libpath) {
00108     if (!libpath.empty()) {
00109       XMLNode mm = mcccfg["ModuleManager"];
00110       if (!mm)
00111         mcccfg.NewChild("ModuleManager", 0);
00112       XMLNode mp = mm["Path"];
00113       for (; (bool)mp; ++mp)
00114         if (mp == libpath)
00115           break;
00116       if (!mp)
00117         mm.NewChild("Path") = libpath;
00118     }
00119     if (!libname.empty()) {
00120       XMLNode pl = mcccfg["Plugins"];
00121       for (; (bool)pl; ++pl)
00122         if (pl["Name"] == libname)
00123           break;
00124       if (!pl)
00125         mcccfg.NewChild("Plugins", 0).NewChild("Name") = libname;
00126     }
00127   }
00128 
00129   ClientTCP::ClientTCP(const BaseConfig& cfg, const std::string& host,
00130                        int port, SecurityLayer sec, int timeout, bool no_delay)
00131     : ClientInterface(cfg),
00132       tcp_entry(NULL),
00133       tls_entry(NULL) {
00134     XMLNode comp = ConfigMakeComponent(xmlcfg["Chain"], "tcp.client", "tcp");
00135     comp.NewAttribute("entry") = "tcp";
00136     comp = comp.NewChild("Connect");
00137     comp.NewChild("Host") = host;
00138     comp.NewChild("Port") = tostring(port);
00139     if(timeout >=  0) comp.NewChild("Timeout") = tostring(timeout);
00140     if(no_delay) comp.NewChild("NoDelay") = "true";
00141 
00142     if ((sec == TLSSec) || (sec == SSL3Sec)) {
00143       comp = ConfigMakeComponent(xmlcfg["Chain"], "tls.client", "tls", "tcp");
00144       if (!cfg.key.empty())
00145         comp.NewChild("KeyPath") = cfg.key;
00146       if (!cfg.cert.empty())
00147         comp.NewChild("CertificatePath") = cfg.cert;
00148       if (!cfg.proxy.empty())
00149         comp.NewChild("ProxyPath") = cfg.proxy;
00150       if (!cfg.cafile.empty())
00151         comp.NewChild("CACertificatePath") = cfg.cafile;
00152       if (!cfg.cadir.empty())
00153         comp.NewChild("CACertificatesDir") = cfg.cadir;
00154       comp.NewAttribute("entry") = "tls";
00155       if (sec == SSL3Sec) 
00156         comp.NewChild("Handshake") = "SSLv3";
00157     }
00158     else if (sec == GSISec) {
00159       comp = ConfigMakeComponent(xmlcfg["Chain"], "gsi.client", "gsi", "tcp");
00160       if (!cfg.key.empty())
00161         comp.NewChild("KeyPath") = cfg.key;
00162       if (!cfg.cert.empty())
00163         comp.NewChild("CertificatePath") = cfg.cert;
00164       if (!cfg.proxy.empty())
00165         comp.NewChild("ProxyPath") = cfg.proxy;
00166       if (!cfg.cafile.empty())
00167         comp.NewChild("CACertificatePath") = cfg.cafile;
00168       if (!cfg.cadir.empty())
00169         comp.NewChild("CACertificatesDir") = cfg.cadir;
00170       comp.NewAttribute("entry") = "gsi";
00171     }
00172   }
00173 
00174   ClientTCP::~ClientTCP() {}
00175 
00176   bool ClientTCP::Load() {
00177     if(!ClientInterface::Load()) return false;
00178     if (!tls_entry)
00179       tls_entry = (*loader)["tls"];
00180     if (!tls_entry)
00181       tls_entry = (*loader)["gsi"];
00182     if (!tcp_entry)
00183       tcp_entry = (*loader)["tcp"];
00184     if((!tls_entry) && (!tcp_entry)) return false;
00185     return true;
00186   }
00187 
00188   MCC_Status ClientTCP::process(PayloadRawInterface *request,
00189                                 PayloadStreamInterface **response, bool tls) {
00190     *response = NULL;
00191     if (!Load())
00192       return MCC_Status();
00193     if (tls && !tls_entry)
00194       return MCC_Status();
00195     if (!tls && !tcp_entry)
00196       return MCC_Status();
00197     MessageAttributes attributes_req;
00198     MessageAttributes attributes_rep;
00199     Message reqmsg;
00200     Message repmsg;
00201     reqmsg.Attributes(&attributes_req);
00202     reqmsg.Context(&context);
00203     reqmsg.Payload(request);
00204     repmsg.Attributes(&attributes_rep);
00205     repmsg.Context(&context);
00206 
00207     MCC_Status r;
00208     if (tls)
00209       r = tls_entry->process(reqmsg, repmsg);
00210     else
00211       r = tcp_entry->process(reqmsg, repmsg);
00212 
00213     if (repmsg.Payload() != NULL)
00214       try {
00215         *response =
00216           dynamic_cast<PayloadStreamInterface*>(repmsg.Payload());
00217       } catch (std::exception&) {
00218         delete repmsg.Payload();
00219       }
00220     return r;
00221   }
00222 
00223   void ClientTCP::AddSecHandler(XMLNode handlercfg, SecurityLayer sec, const std::string& libname, const std::string& libpath) {
00224     if (sec == TLSSec)
00225       ClientInterface::AddSecHandler(
00226         ConfigFindComponent(xmlcfg["Chain"], "tls.client", "tls"),
00227         handlercfg);
00228     else if (sec == GSISec)
00229       ClientInterface::AddSecHandler(
00230         ConfigFindComponent(xmlcfg["Chain"], "gsi.client", "gsi"),
00231         handlercfg);
00232     else
00233       ClientInterface::AddSecHandler(
00234         ConfigFindComponent(xmlcfg["Chain"], "tcp.client", "tcp"),
00235         handlercfg);
00236     for (XMLNode pl = handlercfg["Plugins"]; (bool)pl; ++pl)
00237       AddPlugin(xmlcfg, pl["Name"]);
00238     AddPlugin(xmlcfg, libname, libpath);
00239   }
00240 
00241 
00242   static std::string get_http_proxy(const URL& url) {
00243     if(url.Protocol() == "http") return GetEnv("ARC_HTTP_PROXY");
00244     if(url.Protocol() == "https") return GetEnv("ARC_HTTPS_PROXY");
00245     if(url.Protocol() == "httpg") return GetEnv("ARC_HTTPG_PROXY");
00246     return "";
00247   }
00248 
00249   static std::string get_http_proxy_host(const URL& url, const std::string& proxy_host, int proxy_port) {
00250     if(!proxy_host.empty()) return proxy_host;
00251     std::string proxy = get_http_proxy(url);
00252     if(proxy.empty()) return url.Host();
00253     std::string::size_type p = proxy.find(':');
00254     if(p != std::string::npos) proxy.resize(p);
00255     return proxy;
00256   }
00257 
00258   static int get_http_proxy_port(const URL& url, const std::string& proxy_host, int proxy_port) {
00259     int port = 0;
00260     if(!proxy_host.empty()) {
00261       port = proxy_port;
00262     } else {
00263       std::string proxy = get_http_proxy(url);
00264       if(proxy.empty()) return url.Port();
00265       std::string::size_type p = proxy.find(':');
00266       if(p != std::string::npos) stringto(proxy.substr(p+1),port);
00267     }
00268     if(port == 0) {
00269       if(url.Protocol() == "http") port=HTTP_DEFAULT_PORT;
00270       else if(url.Protocol() == "https") port=HTTPS_DEFAULT_PORT;
00271       else if(url.Protocol() == "httpg") port=HTTPG_DEFAULT_PORT;
00272     }
00273     return port;
00274   }
00275 
00276   ClientHTTP::ClientHTTP(const BaseConfig& cfg, const URL& url, int timeout, const std::string& proxy_host, int proxy_port)
00277     : ClientTCP(cfg,
00278                 get_http_proxy_host(url,proxy_host,proxy_port),
00279                 get_http_proxy_port(url,proxy_host,proxy_port),
00280                 url.Protocol() == "https" ? TLSSec
00281                   : url.Protocol() == "httpg" ? GSISec
00282                     : NoSec,
00283                 timeout,
00284                 url.Option("tcpnodelay") == "yes"),
00285       http_entry(NULL),
00286       default_url(url),
00287       relative_uri(false),
00288       sec(url.Protocol() == "https" ? TLSSec
00289             : url.Protocol() == "httpg" ? GSISec
00290                 : NoSec) {
00291     XMLNode comp = ConfigMakeComponent(xmlcfg["Chain"], "http.client", "http",
00292                                        sec == TLSSec ? "tls" :
00293                                        sec == GSISec ? "gsi" : "tcp");
00294     comp.NewAttribute("entry") = "http";
00295     comp.NewChild("Method") = "POST"; // Override using attributes if needed
00296     comp.NewChild("Endpoint") = url.str();
00297   }
00298 
00299   ClientHTTP::~ClientHTTP() {}
00300 
00301   bool ClientHTTP::Load() {
00302     if(!ClientTCP::Load()) return false;
00303     if (!http_entry)
00304       http_entry = (*loader)["http"];
00305     if (!http_entry) return false;
00306     return true;
00307   }
00308 
00309   MCC_Status ClientHTTP::process(const std::string& method,
00310                                  PayloadRawInterface *request,
00311                                  HTTPClientInfo *info,
00312                                  PayloadRawInterface **response) {
00313     std::multimap<std::string, std::string> attributes;
00314     return process(method, "", attributes, 0, UINT64_MAX, request, info, response);
00315   }
00316 
00317   MCC_Status ClientHTTP::process(const std::string& method,
00318                          std::multimap<std::string, std::string>& attributes,
00319                          PayloadRawInterface *request,
00320                          HTTPClientInfo *info,
00321                          PayloadRawInterface **response) {
00322     return process(method, "", attributes, 0, UINT64_MAX, request, info, response);
00323   }
00324 
00325   MCC_Status ClientHTTP::process(const std::string& method,
00326                                  const std::string& path,
00327                                  PayloadRawInterface *request,
00328                                  HTTPClientInfo *info,
00329                                  PayloadRawInterface **response) {
00330     std::multimap<std::string, std::string> attributes;
00331     return process(method, path, attributes, 0, UINT64_MAX, request, info, response);
00332   }
00333 
00334   MCC_Status ClientHTTP::process(const std::string& method,
00335                          const std::string& path,
00336                          std::multimap<std::string, std::string>& attributes,
00337                          PayloadRawInterface *request,
00338                          HTTPClientInfo *info,
00339                          PayloadRawInterface **response) {
00340     return process(method, path, attributes, 0, UINT64_MAX, request, info, response);
00341   }
00342 
00343   MCC_Status ClientHTTP::process(const std::string& method,
00344                                  const std::string& path,
00345                                  uint64_t range_start, uint64_t range_end,
00346                                  PayloadRawInterface *request,
00347                                  HTTPClientInfo *info,
00348                                  PayloadRawInterface **response) {
00349     std::multimap<std::string, std::string> attributes;
00350     return process(method, path, attributes, range_start, range_end, request, info, response);
00351   }
00352 
00353   MCC_Status ClientHTTP::process(const std::string& method,
00354                          const std::string& path,
00355                          std::multimap<std::string, std::string>& attributes,
00356                          uint64_t range_start, uint64_t range_end,
00357                          PayloadRawInterface *request,
00358                          HTTPClientInfo *info,
00359                          PayloadRawInterface **response) {
00360     *response = NULL;
00361     if (!Load())
00362       return MCC_Status();
00363     if (!http_entry)
00364       return MCC_Status();
00365     MessageAttributes attributes_req;
00366     MessageAttributes attributes_rep;
00367     Message reqmsg;
00368     Message repmsg;
00369     reqmsg.Attributes(&attributes_req);
00370     reqmsg.Context(&context);
00371     reqmsg.Payload(request);
00372     repmsg.Attributes(&attributes_rep);
00373     repmsg.Context(&context);
00374     reqmsg.Attributes()->set("HTTP:METHOD", method);
00375     if (!path.empty()) {
00376       URL url(default_url);
00377       url.ChangePath(path);
00378       if(relative_uri) {
00379         // Workaround for servers which can't handle full URLs in request
00380         reqmsg.Attributes()->set("HTTP:HOST", url.Host() + ":" + tostring(url.Port()));
00381         std::string rpath = url.FullPath();
00382         if(rpath[0] != '/') rpath.insert(0,"/");
00383         reqmsg.Attributes()->set("HTTP:ENDPOINT", rpath);
00384       } else {
00385         reqmsg.Attributes()->set("HTTP:ENDPOINT", url.str());
00386       }
00387     } else {
00388       if(relative_uri) {
00389         reqmsg.Attributes()->set("HTTP:HOST", default_url.Host() + ":" + tostring(default_url.Port()));
00390         std::string rpath = default_url.FullPath();
00391         if(rpath[0] != '/') rpath.insert(0,"/");
00392         reqmsg.Attributes()->set("HTTP:ENDPOINT", rpath);
00393       }
00394     }
00395     if (range_end != UINT64_MAX)
00396       reqmsg.Attributes()->set("HTTP:Range", "bytes=" + tostring(range_start) +
00397                                "-" + tostring(range_end));
00398     else if (range_start != 0)
00399       reqmsg.Attributes()->set("HTTP:Range", "bytes=" +
00400                                tostring(range_start) + "-");
00401     std::map<std::string, std::string>::iterator it;
00402     for (it = attributes.begin(); it != attributes.end(); it++) {
00403       std::string key("HTTP:");
00404       key.append((*it).first);
00405       reqmsg.Attributes()->add(key, (*it).second);
00406     }
00407     MCC_Status r = http_entry->process(reqmsg, repmsg);
00408     if(!r) {
00409       if (repmsg.Payload() != NULL) delete repmsg.Payload();
00410       return r;
00411     };
00412     stringto(repmsg.Attributes()->get("HTTP:CODE"),info->code);
00413     info->reason = repmsg.Attributes()->get("HTTP:REASON");
00414     stringto(repmsg.Attributes()->get("HTTP:content-length"),info->size);
00415     std::string lm;
00416     lm = repmsg.Attributes()->get("HTTP:last-modified");
00417     if (lm.size() > 11)
00418       info->lastModified = lm;
00419     info->type = repmsg.Attributes()->get("HTTP:content-type");
00420     for(AttributeIterator i = repmsg.Attributes()->getAll("HTTP:set-cookie");
00421         i.hasMore();++i) info->cookies.push_back(*i);
00422     info->location = repmsg.Attributes()->get("HTTP:location");
00423     if (repmsg.Payload() != NULL)
00424       try {
00425         *response = dynamic_cast<PayloadRawInterface*>(repmsg.Payload());
00426       } catch (std::exception&) {
00427         delete repmsg.Payload();
00428       }
00429     return r;
00430   }
00431 
00432   void ClientHTTP::AddSecHandler(XMLNode handlercfg, const std::string& libname, const std::string& libpath) {
00433     ClientInterface::AddSecHandler(
00434       ConfigFindComponent(xmlcfg["Chain"], "http.client", "http"),
00435       handlercfg);
00436     for (XMLNode pl = handlercfg["Plugins"]; (bool)pl; ++pl)
00437       AddPlugin(xmlcfg, pl["Name"]);
00438     AddPlugin(xmlcfg, libname, libpath);
00439   }
00440 
00441   ClientSOAP::ClientSOAP(const BaseConfig& cfg, const URL& url, int timeout)
00442     : ClientHTTP(cfg, url, timeout),
00443       soap_entry(NULL) {
00444     XMLNode comp =
00445       ConfigMakeComponent(xmlcfg["Chain"], "soap.client", "soap", "http");
00446     comp.NewAttribute("entry") = "soap";
00447   }
00448 
00449   ClientSOAP::~ClientSOAP() {}
00450 
00451   MCC_Status ClientSOAP::process(PayloadSOAP *request,
00452                                  PayloadSOAP **response) {
00453     return process("", request, response);
00454   }
00455 
00456   bool ClientSOAP::Load() {
00457     if(!ClientHTTP::Load()) return false;
00458     if (!soap_entry)
00459       soap_entry = (*loader)["soap"];
00460     if (!soap_entry) return false;
00461     return true;
00462   }
00463 
00464   MCC_Status ClientSOAP::process(const std::string& action,
00465                                  PayloadSOAP *request,
00466                                  PayloadSOAP **response) {
00467     *response = NULL;
00468     if(!Load())
00469       return MCC_Status();
00470     if (!soap_entry)
00471       return MCC_Status();
00472     MessageAttributes attributes_req;
00473     MessageAttributes attributes_rep;
00474     Message reqmsg;
00475     Message repmsg;
00476     reqmsg.Attributes(&attributes_req);
00477     reqmsg.Context(&context);
00478     reqmsg.Payload(request);
00479     repmsg.Attributes(&attributes_rep);
00480     repmsg.Context(&context);
00481     if (!action.empty())
00482       attributes_req.set("SOAP:ACTION", action);
00483     MCC_Status r = soap_entry->process(reqmsg, repmsg);
00484     if (repmsg.Payload() != NULL)
00485       try {
00486         *response = dynamic_cast<PayloadSOAP*>(repmsg.Payload());
00487       } catch (std::exception&) {
00488         delete repmsg.Payload();
00489       }
00490     return r;
00491   }
00492 
00493   void ClientSOAP::AddSecHandler(XMLNode handlercfg, const std::string& libname, const std::string& libpath) {
00494     ClientInterface::AddSecHandler(
00495       ConfigFindComponent(xmlcfg["Chain"], "soap.client", "soap"),
00496       handlercfg);
00497     for (XMLNode pl = handlercfg["Plugins"]; (bool)pl; ++pl)
00498       AddPlugin(xmlcfg, pl["Name"]);
00499     AddPlugin(xmlcfg, libname, libpath);
00500   }
00501 
00502   SecHandlerConfig::SecHandlerConfig(const std::string& name, const std::string& event)
00503     : XMLNode("<?xml version=\"1.0\"?><SecHandler/>") {
00504     NewAttribute("name") = name;
00505     if (!event.empty())
00506       NewAttribute("event") = event;
00507   }
00508 
00509   DNListHandlerConfig::DNListHandlerConfig(const std::list<std::string>& dns, const std::string& event)
00510     : SecHandlerConfig("arc.authz", event) {
00511     // Loading PDP which deals with DN lists
00512     NewChild("Plugins").NewChild("Name") = "arcshc";
00513     XMLNode pdp = NewChild("PDP");
00514     pdp.NewAttribute("name") = "simplelist.pdp";
00515     for (std::list<std::string>::const_iterator dn = dns.begin();
00516          dn != dns.end(); ++dn)
00517       pdp.NewChild("DN") = (*dn);
00518   }
00519 
00520   void DNListHandlerConfig::AddDN(const std::string& dn) {
00521     XMLNode pdp = operator[]("PDP");
00522     pdp.NewChild("DN") = dn;
00523   }
00524 
00525   ARCPolicyHandlerConfig::ARCPolicyHandlerConfig(const std::string& event)
00526     : SecHandlerConfig("arc.authz", event) {}
00527 
00528   ARCPolicyHandlerConfig::ARCPolicyHandlerConfig(XMLNode policy, const std::string& event)
00529     : SecHandlerConfig("arc.authz", event) {
00530     // Loading PDP which deals with ARC policies
00531     NewChild("Plugins").NewChild("Name") = "arcshc";
00532     XMLNode pdp = NewChild("PDP");
00533     pdp.NewAttribute("name") = "arc.pdp";
00534     pdp.NewChild(policy);
00535   }
00536 
00537   void ARCPolicyHandlerConfig::AddPolicy(XMLNode policy) {
00538     XMLNode pdp = operator[]("PDP");
00539     pdp.NewChild(policy);
00540   }
00541 
00542   void ARCPolicyHandlerConfig::AddPolicy(const std::string& policy) {
00543     XMLNode p(policy);
00544     XMLNode pdp = operator[]("PDP");
00545     pdp.NewChild(p);
00546   }
00547 
00548 
00549 } // namespace Arc