1 /* $Id: yaz-proxy-config.cpp,v 1.8 2004-10-23 23:12:24 adam Exp $
2 Copyright (c) 1998-2004, Index Data.
4 This file is part of the yaz-proxy.
6 YAZ proxy is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
11 YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with YAZ proxy; see the file LICENSE. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 #include <yazproxy/proxy.h>
27 #include <libxml/parser.h>
28 #include <libxml/tree.h>
29 #include <libxslt/xsltutils.h>
30 #include <libxslt/transform.h>
33 class Yaz_ProxyConfigP {
34 friend class Yaz_ProxyConfig;
38 int mycmp(const char *hay, const char *item, size_t len);
39 int match_list(int v, const char *m);
40 int atoi_l(const char **cp);
42 int check_schema(xmlNodePtr ptr, Z_RecordComposition *comp,
43 const char *schema_identifier);
45 xmlNodePtr m_proxyPtr;
46 void return_target_info(xmlNodePtr ptr, const char **url,
47 int *limit_bw, int *limit_pdu, int *limit_req,
48 int *target_idletime, int *client_idletime,
49 int *keepalive_limit_bw, int *keepalive_limit_pdu,
50 int *pre_init, const char **cql2rpn,
51 const char **authentication);
52 void return_limit(xmlNodePtr ptr,
53 int *limit_bw, int *limit_pdu, int *limit_req);
54 int check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
56 xmlNodePtr find_target_node(const char *name, const char *db);
57 xmlNodePtr find_target_db(xmlNodePtr ptr, const char *db);
58 const char *get_text(xmlNodePtr ptr);
59 int check_type_1_attributes(ODR odr, xmlNodePtr ptr,
60 Z_AttributeList *attrs,
62 int check_type_1_structure(ODR odr, xmlNodePtr ptr, Z_RPNStructure *q,
64 int get_explain_ptr(const char *host, const char *db,
65 xmlNodePtr *ptr_target, xmlNodePtr *ptr_explain);
69 Yaz_ProxyConfig::Yaz_ProxyConfig()
71 m_cp = new Yaz_ProxyConfigP;
79 Yaz_ProxyConfig::~Yaz_ProxyConfig()
82 if (!m_cp->m_copy && m_cp->m_docPtr)
83 xmlFreeDoc(m_cp->m_docPtr);
88 int Yaz_ProxyConfig::read_xml(const char *fname)
91 xmlDocPtr ndoc = xmlParseFile(fname);
95 yaz_log(LOG_WARN, "Config file %s not found or parse error", fname);
98 xmlNodePtr proxyPtr = xmlDocGetRootElement(ndoc);
99 if (!proxyPtr || proxyPtr->type != XML_ELEMENT_NODE ||
100 strcmp((const char *) proxyPtr->name, "proxy"))
102 yaz_log(LOG_WARN, "No proxy element in %s", fname);
106 m_cp->m_proxyPtr = proxyPtr;
108 // OK: release previous and make it the current one.
110 xmlFreeDoc(m_cp->m_docPtr);
111 m_cp->m_docPtr = ndoc;
119 const char *Yaz_ProxyConfigP::get_text(xmlNodePtr ptr)
121 for(ptr = ptr->children; ptr; ptr = ptr->next)
122 if (ptr->type == XML_TEXT_NODE)
124 xmlChar *t = ptr->content;
129 return (const char *) t;
137 void Yaz_ProxyConfigP::return_limit(xmlNodePtr ptr,
142 for (ptr = ptr->children; ptr; ptr = ptr->next)
144 if (ptr->type == XML_ELEMENT_NODE
145 && !strcmp((const char *) ptr->name, "bandwidth"))
147 const char *t = get_text(ptr);
151 if (ptr->type == XML_ELEMENT_NODE
152 && !strcmp((const char *) ptr->name, "retrieve"))
154 const char *t = get_text(ptr);
156 *limit_req = atoi(t);
158 if (ptr->type == XML_ELEMENT_NODE
159 && !strcmp((const char *) ptr->name, "pdu"))
161 const char *t = get_text(ptr);
163 *limit_pdu = atoi(t);
170 void Yaz_ProxyConfigP::return_target_info(xmlNodePtr ptr,
175 int *target_idletime,
176 int *client_idletime,
177 int *keepalive_limit_bw,
178 int *keepalive_limit_pdu,
180 const char **cql2rpn,
181 const char **authentication)
186 for (; ptr; ptr = ptr->next)
188 if (ptr->type == XML_ELEMENT_NODE
189 && !strcmp((const char *) ptr->name, "preinit"))
191 const char *v = get_text(ptr);
192 *pre_init = v ? atoi(v) : 1;
194 if (ptr->type == XML_ELEMENT_NODE
195 && !strcmp((const char *) ptr->name, "url"))
197 const char *t = get_text(ptr);
198 if (t && no_url < MAX_ZURL_PLEX)
204 if (ptr->type == XML_ELEMENT_NODE
205 && !strcmp((const char *) ptr->name, "keepalive"))
208 *keepalive_limit_bw = 500000;
209 *keepalive_limit_pdu = 1000;
210 return_limit(ptr, keepalive_limit_bw, keepalive_limit_pdu,
213 if (ptr->type == XML_ELEMENT_NODE
214 && !strcmp((const char *) ptr->name, "limit"))
215 return_limit(ptr, limit_bw, limit_pdu, limit_req);
216 if (ptr->type == XML_ELEMENT_NODE
217 && !strcmp((const char *) ptr->name, "target-timeout"))
219 const char *t = get_text(ptr);
222 *target_idletime = atoi(t);
223 if (*target_idletime < 0)
224 *target_idletime = 0;
227 if (ptr->type == XML_ELEMENT_NODE
228 && !strcmp((const char *) ptr->name, "client-timeout"))
230 const char *t = get_text(ptr);
233 *client_idletime = atoi(t);
234 if (*client_idletime < 0)
235 *client_idletime = 0;
238 if (ptr->type == XML_ELEMENT_NODE
239 && !strcmp((const char *) ptr->name, "cql2rpn"))
241 const char *t = get_text(ptr);
245 if (ptr->type == XML_ELEMENT_NODE
246 && !strcmp((const char *) ptr->name, "authentication"))
248 const char *t = get_text(ptr);
256 int Yaz_ProxyConfigP::atoi_l(const char **cp)
259 while (**cp && isdigit(**cp))
261 v = v*10 + (**cp - '0');
267 int Yaz_ProxyConfigP::match_list(int v, const char *m)
271 while(*m && isspace(*m))
282 if (v >= l && v <= h)
291 int Yaz_ProxyConfigP::check_type_1_attributes(ODR odr, xmlNodePtr ptrl,
292 Z_AttributeList *attrs,
296 for (i = 0; i<attrs->num_attributes; i++)
298 Z_AttributeElement *el = attrs->attributes[i];
300 if (!el->attributeType)
302 int type = *el->attributeType;
305 if (el->which == Z_AttributeValue_numeric && el->value.numeric)
306 value = el->value.numeric;
309 for(ptr = ptrl->children; ptr; ptr = ptr->next)
311 if (ptr->type == XML_ELEMENT_NODE &&
312 !strcmp((const char *) ptr->name, "attribute"))
314 const char *match_type = 0;
315 const char *match_value = 0;
316 const char *match_error = 0;
317 struct _xmlAttr *attr;
318 for (attr = ptr->properties; attr; attr = attr->next)
320 if (!strcmp((const char *) attr->name, "type") &&
321 attr->children && attr->children->type == XML_TEXT_NODE)
322 match_type = (const char *) attr->children->content;
323 if (!strcmp((const char *) attr->name, "value") &&
324 attr->children && attr->children->type == XML_TEXT_NODE)
325 match_value = (const char *) attr->children->content;
326 if (!strcmp((const char *) attr->name, "error") &&
327 attr->children && attr->children->type == XML_TEXT_NODE)
328 match_error = (const char *) attr->children->content;
330 if (match_type && match_value)
332 char addinfo_str[20];
333 if (!match_list(type, match_type))
337 if (!strcmp(match_type, "*"))
338 sprintf (addinfo_str, "%d", type);
341 if (!match_list(*value, match_value))
343 sprintf (addinfo_str, "%d", *value);
351 *addinfo = odr_strdup(odr, addinfo_str);
352 return atoi(match_error);
364 int Yaz_ProxyConfigP::check_type_1_structure(ODR odr, xmlNodePtr ptr,
368 if (q->which == Z_RPNStructure_complex)
370 int e = check_type_1_structure(odr, ptr, q->u.complex->s1, addinfo);
373 e = check_type_1_structure(odr, ptr, q->u.complex->s2, addinfo);
376 else if (q->which == Z_RPNStructure_simple)
378 if (q->u.simple->which == Z_Operand_APT)
380 return check_type_1_attributes(
381 odr, ptr, q->u.simple->u.attributesPlusTerm->attributes,
390 int Yaz_ProxyConfigP::check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
393 // possibly check for Bib-1
394 return check_type_1_structure(odr, ptr, query->RPNStructure, addinfo);
398 int Yaz_ProxyConfig::check_query(ODR odr, const char *name, Z_Query *query,
404 ptr = m_cp->find_target_node(name, 0);
407 if (query->which == Z_Query_type_1 || query->which == Z_Query_type_101)
408 return m_cp->check_type_1(odr, ptr, query->u.type_1, addinfo);
415 int Yaz_ProxyConfigP::check_schema(xmlNodePtr ptr, Z_RecordComposition *comp,
416 const char *schema_identifier)
419 int default_match = 1;
420 if (comp && comp->which == Z_RecordComp_simple &&
421 comp->u.simple && comp->u.simple->which == Z_ElementSetNames_generic)
423 esn = comp->u.simple->u.generic;
425 // if no ESN/schema was given accept..
428 // check if schema identifier match
429 if (schema_identifier && !strcmp(esn, schema_identifier))
431 // Check each name element
432 for (; ptr; ptr = ptr->next)
434 if (ptr->type == XML_ELEMENT_NODE
435 && !strcmp((const char *) ptr->name, "name"))
437 xmlNodePtr tptr = ptr->children;
439 for (; tptr; tptr = tptr->next)
440 if (tptr->type == XML_TEXT_NODE && tptr->content)
442 xmlChar *t = tptr->content;
443 while (*t && isspace(*t))
446 while (esn[i] && esn[i] == t[i])
448 if (!esn[i] && (!t[i] || isspace(t[i])))
453 return default_match;
457 int Yaz_ProxyConfig::check_syntax(ODR odr, const char *name,
458 Odr_oid *syntax, Z_RecordComposition *comp,
460 char **stylesheet, char **schema,
462 char **backend_charset)
476 xfree (*backend_type);
481 xfree (*backend_charset);
482 *backend_charset = 0;
485 int syntax_has_matched = 0;
488 ptr = m_cp->find_target_node(name, 0);
491 for(ptr = ptr->children; ptr; ptr = ptr->next)
493 if (ptr->type == XML_ELEMENT_NODE &&
494 !strcmp((const char *) ptr->name, "syntax"))
496 int match = 0; // if we match record syntax
497 const char *match_type = 0;
498 const char *match_error = 0;
499 const char *match_marcxml = 0;
500 const char *match_stylesheet = 0;
501 const char *match_identifier = 0;
502 const char *match_backend_type = 0;
503 const char *match_backend_charset = 0;
504 struct _xmlAttr *attr;
505 for (attr = ptr->properties; attr; attr = attr->next)
507 if (!strcmp((const char *) attr->name, "type") &&
508 attr->children && attr->children->type == XML_TEXT_NODE)
509 match_type = (const char *) attr->children->content;
510 if (!strcmp((const char *) attr->name, "error") &&
511 attr->children && attr->children->type == XML_TEXT_NODE)
512 match_error = (const char *) attr->children->content;
513 if (!strcmp((const char *) attr->name, "marcxml") &&
514 attr->children && attr->children->type == XML_TEXT_NODE)
515 match_marcxml = (const char *) attr->children->content;
516 if (!strcmp((const char *) attr->name, "stylesheet") &&
517 attr->children && attr->children->type == XML_TEXT_NODE)
518 match_stylesheet = (const char *) attr->children->content;
519 if (!strcmp((const char *) attr->name, "identifier") &&
520 attr->children && attr->children->type == XML_TEXT_NODE)
521 match_identifier = (const char *) attr->children->content;
522 if (!strcmp((const char *) attr->name, "backendtype") &&
523 attr->children && attr->children->type == XML_TEXT_NODE)
524 match_backend_type = (const char *)
525 attr->children->content;
526 if (!strcmp((const char *) attr->name, "backendcharset") &&
527 attr->children && attr->children->type == XML_TEXT_NODE)
528 match_backend_charset = (const char *)
529 attr->children->content;
533 if (!strcmp(match_type, "*"))
535 else if (!strcmp(match_type, "none"))
542 int match_oid[OID_SIZE];
543 oid_name_to_oid(CLASS_RECSYN, match_type, match_oid);
544 if (oid_oidcmp(match_oid, syntax) == 0)
551 syntax_has_matched = 1;
552 match = m_cp->check_schema(ptr->children, comp,
557 if (stylesheet && match_stylesheet)
560 *stylesheet = xstrdup(match_stylesheet);
562 if (schema && match_identifier)
565 *schema = xstrdup(match_identifier);
567 if (backend_type && match_backend_type)
569 xfree(*backend_type);
570 *backend_type = xstrdup(match_backend_type);
572 if (backend_charset && match_backend_charset)
574 xfree(*backend_charset);
575 *backend_charset = xstrdup(match_backend_charset);
583 if (syntax_has_matched) // if syntax OK, bad schema/ESN
587 char dotoid_str[100];
588 oid_to_dotstring(syntax, dotoid_str);
589 *addinfo = odr_strdup(odr, dotoid_str);
591 return atoi(match_error);
602 xmlNodePtr Yaz_ProxyConfigP::find_target_db(xmlNodePtr ptr, const char *db)
609 for (dptr = ptr->children; dptr; dptr = dptr->next)
610 if (dptr->type == XML_ELEMENT_NODE &&
611 !strcmp((const char *) dptr->name, "database"))
613 struct _xmlAttr *attr;
614 for (attr = dptr->properties; attr; attr = attr->next)
615 if (!strcmp((const char *) attr->name, "name"))
618 && attr->children->type==XML_TEXT_NODE
619 && attr->children->content
620 && (!strcmp((const char *) attr->children->content, db)
621 || !strcmp((const char *) attr->children->content,
629 xmlNodePtr Yaz_ProxyConfigP::find_target_node(const char *name, const char *db)
634 for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
636 if (ptr->type == XML_ELEMENT_NODE &&
637 !strcmp((const char *) ptr->name, "target"))
642 // <target default="1"> ?
643 struct _xmlAttr *attr;
644 for (attr = ptr->properties; attr; attr = attr->next)
645 if (!strcmp((const char *) attr->name, "default") &&
646 attr->children && attr->children->type == XML_TEXT_NODE)
648 xmlChar *t = attr->children->content;
651 return find_target_db(ptr, db);
657 // <target name="name"> ?
658 struct _xmlAttr *attr;
659 for (attr = ptr->properties; attr; attr = attr->next)
660 if (!strcmp((const char *) attr->name, "name"))
663 && attr->children->type==XML_TEXT_NODE
664 && attr->children->content
665 && (!strcmp((const char *) attr->children->content,
667 || !strcmp((const char *) attr->children->content,
670 return find_target_db(ptr, db);
680 int Yaz_ProxyConfig::get_target_no(int no,
686 int *target_idletime,
687 int *client_idletime,
689 int *keepalive_limit_bw,
690 int *keepalive_limit_pdu,
692 const char **cql2rpn,
693 const char **authentication)
697 if (!m_cp->m_proxyPtr)
700 for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
701 if (ptr->type == XML_ELEMENT_NODE &&
702 !strcmp((const char *) ptr->name, "target"))
706 struct _xmlAttr *attr;
707 for (attr = ptr->properties; attr; attr = attr->next)
708 if (!strcmp((const char *) attr->name, "name"))
711 && attr->children->type==XML_TEXT_NODE
712 && attr->children->content)
713 *name = (const char *) attr->children->content;
715 m_cp->return_target_info(
717 limit_bw, limit_pdu, limit_req,
718 target_idletime, client_idletime,
719 keepalive_limit_bw, keepalive_limit_pdu,
720 pre_init, cql2rpn, authentication);
729 int Yaz_ProxyConfigP::mycmp(const char *hay, const char *item, size_t len)
731 if (len == strlen(item) && memcmp(hay, item, len) == 0)
736 void Yaz_ProxyConfig::get_generic_info(int *log_mask,
741 if (!m_cp->m_proxyPtr)
743 for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
745 if (ptr->type == XML_ELEMENT_NODE
746 && !strcmp((const char *) ptr->name, "log"))
748 const char *v = m_cp->get_text(ptr);
753 while (*cp && *cp != ',' && !isspace(*cp))
756 if (m_cp->mycmp(v, "client-apdu", len))
757 *log_mask |= PROXY_LOG_APDU_CLIENT;
758 if (m_cp->mycmp(v, "server-apdu", len))
759 *log_mask |= PROXY_LOG_APDU_SERVER;
760 if (m_cp->mycmp(v, "client-requests", len))
761 *log_mask |= PROXY_LOG_REQ_CLIENT;
762 if (m_cp->mycmp(v, "server-requests", len))
763 *log_mask |= PROXY_LOG_REQ_SERVER;
765 *log_mask |= atoi(v);
768 while (*cp && isspace(*cp))
773 if (ptr->type == XML_ELEMENT_NODE &&
774 !strcmp((const char *) ptr->name, "max-clients"))
776 const char *t = m_cp->get_text(ptr);
779 *max_clients = atoi(t);
780 if (*max_clients < 1)
789 int Yaz_ProxyConfigP::get_explain_ptr(const char *host, const char *db,
790 xmlNodePtr *ptr_target,
791 xmlNodePtr *ptr_explain)
798 for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
800 if (ptr->type == XML_ELEMENT_NODE &&
801 !strcmp((const char *) ptr->name, "target"))
804 xmlNodePtr ptr = (*ptr_target)->children;
805 for (; ptr; ptr = ptr->next)
807 if (ptr->type == XML_ELEMENT_NODE &&
808 !strcmp((const char *) ptr->name, "explain"))
811 xmlNodePtr ptr = (*ptr_explain)->children;
813 for (; ptr; ptr = ptr->next)
814 if (ptr->type == XML_ELEMENT_NODE &&
815 !strcmp((const char *) ptr->name, "serverInfo"))
819 for (ptr = ptr->children; ptr; ptr = ptr->next)
820 if (ptr->type == XML_ELEMENT_NODE &&
821 !strcmp((const char *) ptr->name, "database"))
826 for (ptr = ptr->children; ptr; ptr = ptr->next)
827 if (ptr->type == XML_TEXT_NODE &&
829 !strcmp((const char *) ptr->content, db))
842 const char *Yaz_ProxyConfig::get_explain_name(const char *db,
843 const char **backend_db)
846 xmlNodePtr ptr_target, ptr_explain;
847 if (m_cp->get_explain_ptr(0, db, &ptr_target, &ptr_explain)
850 struct _xmlAttr *attr;
851 const char *name = 0;
853 for (attr = ptr_target->properties; attr; attr = attr->next)
854 if (!strcmp((const char *) attr->name, "name")
856 && attr->children->type==XML_TEXT_NODE
857 && attr->children->content
858 && attr->children->content[0])
860 name = (const char *)attr->children->content;
865 for (attr = ptr_target->properties; attr; attr = attr->next)
866 if (!strcmp((const char *) attr->name, "database"))
869 && attr->children->type==XML_TEXT_NODE
870 && attr->children->content)
871 *backend_db = (const char *) attr->children->content;
880 char *Yaz_ProxyConfig::get_explain_doc(ODR odr, const char *name,
881 const char *db, int *len)
884 xmlNodePtr ptr_target, ptr_explain;
885 if (m_cp->get_explain_ptr(0 /* host */, db, &ptr_target, &ptr_explain))
887 xmlNodePtr ptr2 = xmlCopyNode(ptr_explain, 1);
889 xmlDocPtr doc = xmlNewDoc((const xmlChar *) "1.0");
891 xmlDocSetRootElement(doc, ptr2);
894 xmlDocDumpMemory(doc, &buf_out, len);
895 char *content = (char*) odr_malloc(odr, *len);
896 memcpy(content, buf_out, *len);
906 void Yaz_ProxyConfig::get_target_info(const char *name,
911 int *target_idletime,
912 int *client_idletime,
914 int *keepalive_limit_bw,
915 int *keepalive_limit_pdu,
917 const char **cql2rpn,
918 const char **authentication)
922 if (!m_cp->m_proxyPtr)
929 for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
931 if (ptr->type == XML_ELEMENT_NODE &&
932 !strcmp((const char *) ptr->name, "max-clients"))
934 const char *t = m_cp->get_text(ptr);
937 *max_clients = atoi(t);
938 if (*max_clients < 1)
943 ptr = m_cp->find_target_node(name, 0);
951 m_cp->return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
952 target_idletime, client_idletime,
953 keepalive_limit_bw, keepalive_limit_pdu,
954 pre_init, cql2rpn, authentication);