1 /* $Id: yaz-proxy-config.cpp,v 1.7 2004-10-18 22:10:57 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 void return_limit(xmlNodePtr ptr,
52 int *limit_bw, int *limit_pdu, int *limit_req);
53 int check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
55 xmlNodePtr find_target_node(const char *name, const char *db);
56 xmlNodePtr find_target_db(xmlNodePtr ptr, const char *db);
57 const char *get_text(xmlNodePtr ptr);
58 int check_type_1_attributes(ODR odr, xmlNodePtr ptr,
59 Z_AttributeList *attrs,
61 int check_type_1_structure(ODR odr, xmlNodePtr ptr, Z_RPNStructure *q,
63 int get_explain_ptr(const char *host, const char *db,
64 xmlNodePtr *ptr_target, xmlNodePtr *ptr_explain);
68 Yaz_ProxyConfig::Yaz_ProxyConfig()
70 m_cp = new Yaz_ProxyConfigP;
78 Yaz_ProxyConfig::~Yaz_ProxyConfig()
81 if (!m_cp->m_copy && m_cp->m_docPtr)
82 xmlFreeDoc(m_cp->m_docPtr);
87 int Yaz_ProxyConfig::read_xml(const char *fname)
90 xmlDocPtr ndoc = xmlParseFile(fname);
94 yaz_log(LOG_WARN, "Config file %s not found or parse error", fname);
97 xmlNodePtr proxyPtr = xmlDocGetRootElement(ndoc);
98 if (!proxyPtr || proxyPtr->type != XML_ELEMENT_NODE ||
99 strcmp((const char *) proxyPtr->name, "proxy"))
101 yaz_log(LOG_WARN, "No proxy element in %s", fname);
105 m_cp->m_proxyPtr = proxyPtr;
107 // OK: release previous and make it the current one.
109 xmlFreeDoc(m_cp->m_docPtr);
110 m_cp->m_docPtr = ndoc;
118 const char *Yaz_ProxyConfigP::get_text(xmlNodePtr ptr)
120 for(ptr = ptr->children; ptr; ptr = ptr->next)
121 if (ptr->type == XML_TEXT_NODE)
123 xmlChar *t = ptr->content;
128 return (const char *) t;
136 void Yaz_ProxyConfigP::return_limit(xmlNodePtr ptr,
141 for (ptr = ptr->children; ptr; ptr = ptr->next)
143 if (ptr->type == XML_ELEMENT_NODE
144 && !strcmp((const char *) ptr->name, "bandwidth"))
146 const char *t = get_text(ptr);
150 if (ptr->type == XML_ELEMENT_NODE
151 && !strcmp((const char *) ptr->name, "retrieve"))
153 const char *t = get_text(ptr);
155 *limit_req = atoi(t);
157 if (ptr->type == XML_ELEMENT_NODE
158 && !strcmp((const char *) ptr->name, "pdu"))
160 const char *t = get_text(ptr);
162 *limit_pdu = atoi(t);
169 void Yaz_ProxyConfigP::return_target_info(xmlNodePtr ptr,
174 int *target_idletime,
175 int *client_idletime,
176 int *keepalive_limit_bw,
177 int *keepalive_limit_pdu,
179 const char **cql2rpn)
184 for (; ptr; ptr = ptr->next)
186 if (ptr->type == XML_ELEMENT_NODE
187 && !strcmp((const char *) ptr->name, "preinit"))
189 const char *v = get_text(ptr);
190 *pre_init = v ? atoi(v) : 1;
192 if (ptr->type == XML_ELEMENT_NODE
193 && !strcmp((const char *) ptr->name, "url"))
195 const char *t = get_text(ptr);
196 if (t && no_url < MAX_ZURL_PLEX)
202 if (ptr->type == XML_ELEMENT_NODE
203 && !strcmp((const char *) ptr->name, "keepalive"))
206 *keepalive_limit_bw = 500000;
207 *keepalive_limit_pdu = 1000;
208 return_limit(ptr, keepalive_limit_bw, keepalive_limit_pdu,
211 if (ptr->type == XML_ELEMENT_NODE
212 && !strcmp((const char *) ptr->name, "limit"))
213 return_limit(ptr, limit_bw, limit_pdu, limit_req);
214 if (ptr->type == XML_ELEMENT_NODE
215 && !strcmp((const char *) ptr->name, "target-timeout"))
217 const char *t = get_text(ptr);
220 *target_idletime = atoi(t);
221 if (*target_idletime < 0)
222 *target_idletime = 0;
225 if (ptr->type == XML_ELEMENT_NODE
226 && !strcmp((const char *) ptr->name, "client-timeout"))
228 const char *t = get_text(ptr);
231 *client_idletime = atoi(t);
232 if (*client_idletime < 0)
233 *client_idletime = 0;
236 if (ptr->type == XML_ELEMENT_NODE
237 && !strcmp((const char *) ptr->name, "cql2rpn"))
239 const char *t = get_text(ptr);
247 int Yaz_ProxyConfigP::atoi_l(const char **cp)
250 while (**cp && isdigit(**cp))
252 v = v*10 + (**cp - '0');
258 int Yaz_ProxyConfigP::match_list(int v, const char *m)
262 while(*m && isspace(*m))
273 if (v >= l && v <= h)
282 int Yaz_ProxyConfigP::check_type_1_attributes(ODR odr, xmlNodePtr ptrl,
283 Z_AttributeList *attrs,
287 for (i = 0; i<attrs->num_attributes; i++)
289 Z_AttributeElement *el = attrs->attributes[i];
291 if (!el->attributeType)
293 int type = *el->attributeType;
296 if (el->which == Z_AttributeValue_numeric && el->value.numeric)
297 value = el->value.numeric;
300 for(ptr = ptrl->children; ptr; ptr = ptr->next)
302 if (ptr->type == XML_ELEMENT_NODE &&
303 !strcmp((const char *) ptr->name, "attribute"))
305 const char *match_type = 0;
306 const char *match_value = 0;
307 const char *match_error = 0;
308 struct _xmlAttr *attr;
309 for (attr = ptr->properties; attr; attr = attr->next)
311 if (!strcmp((const char *) attr->name, "type") &&
312 attr->children && attr->children->type == XML_TEXT_NODE)
313 match_type = (const char *) attr->children->content;
314 if (!strcmp((const char *) attr->name, "value") &&
315 attr->children && attr->children->type == XML_TEXT_NODE)
316 match_value = (const char *) attr->children->content;
317 if (!strcmp((const char *) attr->name, "error") &&
318 attr->children && attr->children->type == XML_TEXT_NODE)
319 match_error = (const char *) attr->children->content;
321 if (match_type && match_value)
323 char addinfo_str[20];
324 if (!match_list(type, match_type))
328 if (!strcmp(match_type, "*"))
329 sprintf (addinfo_str, "%d", type);
332 if (!match_list(*value, match_value))
334 sprintf (addinfo_str, "%d", *value);
342 *addinfo = odr_strdup(odr, addinfo_str);
343 return atoi(match_error);
355 int Yaz_ProxyConfigP::check_type_1_structure(ODR odr, xmlNodePtr ptr,
359 if (q->which == Z_RPNStructure_complex)
361 int e = check_type_1_structure(odr, ptr, q->u.complex->s1, addinfo);
364 e = check_type_1_structure(odr, ptr, q->u.complex->s2, addinfo);
367 else if (q->which == Z_RPNStructure_simple)
369 if (q->u.simple->which == Z_Operand_APT)
371 return check_type_1_attributes(
372 odr, ptr, q->u.simple->u.attributesPlusTerm->attributes,
381 int Yaz_ProxyConfigP::check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
384 // possibly check for Bib-1
385 return check_type_1_structure(odr, ptr, query->RPNStructure, addinfo);
389 int Yaz_ProxyConfig::check_query(ODR odr, const char *name, Z_Query *query,
395 ptr = m_cp->find_target_node(name, 0);
398 if (query->which == Z_Query_type_1 || query->which == Z_Query_type_101)
399 return m_cp->check_type_1(odr, ptr, query->u.type_1, addinfo);
406 int Yaz_ProxyConfigP::check_schema(xmlNodePtr ptr, Z_RecordComposition *comp,
407 const char *schema_identifier)
410 int default_match = 1;
411 if (comp && comp->which == Z_RecordComp_simple &&
412 comp->u.simple && comp->u.simple->which == Z_ElementSetNames_generic)
414 esn = comp->u.simple->u.generic;
416 // if no ESN/schema was given accept..
419 // check if schema identifier match
420 if (schema_identifier && !strcmp(esn, schema_identifier))
422 // Check each name element
423 for (; ptr; ptr = ptr->next)
425 if (ptr->type == XML_ELEMENT_NODE
426 && !strcmp((const char *) ptr->name, "name"))
428 xmlNodePtr tptr = ptr->children;
430 for (; tptr; tptr = tptr->next)
431 if (tptr->type == XML_TEXT_NODE && tptr->content)
433 xmlChar *t = tptr->content;
434 while (*t && isspace(*t))
437 while (esn[i] && esn[i] == t[i])
439 if (!esn[i] && (!t[i] || isspace(t[i])))
444 return default_match;
448 int Yaz_ProxyConfig::check_syntax(ODR odr, const char *name,
449 Odr_oid *syntax, Z_RecordComposition *comp,
451 char **stylesheet, char **schema,
453 char **backend_charset)
467 xfree (*backend_type);
472 xfree (*backend_charset);
473 *backend_charset = 0;
476 int syntax_has_matched = 0;
479 ptr = m_cp->find_target_node(name, 0);
482 for(ptr = ptr->children; ptr; ptr = ptr->next)
484 if (ptr->type == XML_ELEMENT_NODE &&
485 !strcmp((const char *) ptr->name, "syntax"))
487 int match = 0; // if we match record syntax
488 const char *match_type = 0;
489 const char *match_error = 0;
490 const char *match_marcxml = 0;
491 const char *match_stylesheet = 0;
492 const char *match_identifier = 0;
493 const char *match_backend_type = 0;
494 const char *match_backend_charset = 0;
495 struct _xmlAttr *attr;
496 for (attr = ptr->properties; attr; attr = attr->next)
498 if (!strcmp((const char *) attr->name, "type") &&
499 attr->children && attr->children->type == XML_TEXT_NODE)
500 match_type = (const char *) attr->children->content;
501 if (!strcmp((const char *) attr->name, "error") &&
502 attr->children && attr->children->type == XML_TEXT_NODE)
503 match_error = (const char *) attr->children->content;
504 if (!strcmp((const char *) attr->name, "marcxml") &&
505 attr->children && attr->children->type == XML_TEXT_NODE)
506 match_marcxml = (const char *) attr->children->content;
507 if (!strcmp((const char *) attr->name, "stylesheet") &&
508 attr->children && attr->children->type == XML_TEXT_NODE)
509 match_stylesheet = (const char *) attr->children->content;
510 if (!strcmp((const char *) attr->name, "identifier") &&
511 attr->children && attr->children->type == XML_TEXT_NODE)
512 match_identifier = (const char *) attr->children->content;
513 if (!strcmp((const char *) attr->name, "backendtype") &&
514 attr->children && attr->children->type == XML_TEXT_NODE)
515 match_backend_type = (const char *)
516 attr->children->content;
517 if (!strcmp((const char *) attr->name, "backendcharset") &&
518 attr->children && attr->children->type == XML_TEXT_NODE)
519 match_backend_charset = (const char *)
520 attr->children->content;
524 if (!strcmp(match_type, "*"))
526 else if (!strcmp(match_type, "none"))
533 int match_oid[OID_SIZE];
534 oid_name_to_oid(CLASS_RECSYN, match_type, match_oid);
535 if (oid_oidcmp(match_oid, syntax) == 0)
542 syntax_has_matched = 1;
543 match = m_cp->check_schema(ptr->children, comp,
548 if (stylesheet && match_stylesheet)
551 *stylesheet = xstrdup(match_stylesheet);
553 if (schema && match_identifier)
556 *schema = xstrdup(match_identifier);
558 if (backend_type && match_backend_type)
560 xfree(*backend_type);
561 *backend_type = xstrdup(match_backend_type);
563 if (backend_charset && match_backend_charset)
565 xfree(*backend_charset);
566 *backend_charset = xstrdup(match_backend_charset);
574 if (syntax_has_matched) // if syntax OK, bad schema/ESN
578 char dotoid_str[100];
579 oid_to_dotstring(syntax, dotoid_str);
580 *addinfo = odr_strdup(odr, dotoid_str);
582 return atoi(match_error);
593 xmlNodePtr Yaz_ProxyConfigP::find_target_db(xmlNodePtr ptr, const char *db)
600 for (dptr = ptr->children; dptr; dptr = dptr->next)
601 if (dptr->type == XML_ELEMENT_NODE &&
602 !strcmp((const char *) dptr->name, "database"))
604 struct _xmlAttr *attr;
605 for (attr = dptr->properties; attr; attr = attr->next)
606 if (!strcmp((const char *) attr->name, "name"))
609 && attr->children->type==XML_TEXT_NODE
610 && attr->children->content
611 && (!strcmp((const char *) attr->children->content, db)
612 || !strcmp((const char *) attr->children->content,
620 xmlNodePtr Yaz_ProxyConfigP::find_target_node(const char *name, const char *db)
625 for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
627 if (ptr->type == XML_ELEMENT_NODE &&
628 !strcmp((const char *) ptr->name, "target"))
633 // <target default="1"> ?
634 struct _xmlAttr *attr;
635 for (attr = ptr->properties; attr; attr = attr->next)
636 if (!strcmp((const char *) attr->name, "default") &&
637 attr->children && attr->children->type == XML_TEXT_NODE)
639 xmlChar *t = attr->children->content;
642 return find_target_db(ptr, db);
648 // <target name="name"> ?
649 struct _xmlAttr *attr;
650 for (attr = ptr->properties; attr; attr = attr->next)
651 if (!strcmp((const char *) attr->name, "name"))
654 && attr->children->type==XML_TEXT_NODE
655 && attr->children->content
656 && (!strcmp((const char *) attr->children->content,
658 || !strcmp((const char *) attr->children->content,
661 return find_target_db(ptr, db);
671 int Yaz_ProxyConfig::get_target_no(int no,
677 int *target_idletime,
678 int *client_idletime,
680 int *keepalive_limit_bw,
681 int *keepalive_limit_pdu,
683 const char **cql2rpn)
687 if (!m_cp->m_proxyPtr)
690 for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
691 if (ptr->type == XML_ELEMENT_NODE &&
692 !strcmp((const char *) ptr->name, "target"))
696 struct _xmlAttr *attr;
697 for (attr = ptr->properties; attr; attr = attr->next)
698 if (!strcmp((const char *) attr->name, "name"))
701 && attr->children->type==XML_TEXT_NODE
702 && attr->children->content)
703 *name = (const char *) attr->children->content;
705 m_cp->return_target_info(
707 limit_bw, limit_pdu, limit_req,
708 target_idletime, client_idletime,
709 keepalive_limit_bw, keepalive_limit_pdu,
719 int Yaz_ProxyConfigP::mycmp(const char *hay, const char *item, size_t len)
721 if (len == strlen(item) && memcmp(hay, item, len) == 0)
726 void Yaz_ProxyConfig::get_generic_info(int *log_mask,
731 if (!m_cp->m_proxyPtr)
733 for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
735 if (ptr->type == XML_ELEMENT_NODE
736 && !strcmp((const char *) ptr->name, "log"))
738 const char *v = m_cp->get_text(ptr);
743 while (*cp && *cp != ',' && !isspace(*cp))
746 if (m_cp->mycmp(v, "client-apdu", len))
747 *log_mask |= PROXY_LOG_APDU_CLIENT;
748 if (m_cp->mycmp(v, "server-apdu", len))
749 *log_mask |= PROXY_LOG_APDU_SERVER;
750 if (m_cp->mycmp(v, "client-requests", len))
751 *log_mask |= PROXY_LOG_REQ_CLIENT;
752 if (m_cp->mycmp(v, "server-requests", len))
753 *log_mask |= PROXY_LOG_REQ_SERVER;
755 *log_mask |= atoi(v);
758 while (*cp && isspace(*cp))
763 if (ptr->type == XML_ELEMENT_NODE &&
764 !strcmp((const char *) ptr->name, "max-clients"))
766 const char *t = m_cp->get_text(ptr);
769 *max_clients = atoi(t);
770 if (*max_clients < 1)
779 int Yaz_ProxyConfigP::get_explain_ptr(const char *host, const char *db,
780 xmlNodePtr *ptr_target,
781 xmlNodePtr *ptr_explain)
788 for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
790 if (ptr->type == XML_ELEMENT_NODE &&
791 !strcmp((const char *) ptr->name, "target"))
794 xmlNodePtr ptr = (*ptr_target)->children;
795 for (; ptr; ptr = ptr->next)
797 if (ptr->type == XML_ELEMENT_NODE &&
798 !strcmp((const char *) ptr->name, "explain"))
801 xmlNodePtr ptr = (*ptr_explain)->children;
803 for (; ptr; ptr = ptr->next)
804 if (ptr->type == XML_ELEMENT_NODE &&
805 !strcmp((const char *) ptr->name, "serverInfo"))
809 for (ptr = ptr->children; ptr; ptr = ptr->next)
810 if (ptr->type == XML_ELEMENT_NODE &&
811 !strcmp((const char *) ptr->name, "database"))
816 for (ptr = ptr->children; ptr; ptr = ptr->next)
817 if (ptr->type == XML_TEXT_NODE &&
819 !strcmp((const char *) ptr->content, db))
832 const char *Yaz_ProxyConfig::get_explain_name(const char *db,
833 const char **backend_db)
836 xmlNodePtr ptr_target, ptr_explain;
837 if (m_cp->get_explain_ptr(0, db, &ptr_target, &ptr_explain)
840 struct _xmlAttr *attr;
841 const char *name = 0;
843 for (attr = ptr_target->properties; attr; attr = attr->next)
844 if (!strcmp((const char *) attr->name, "name")
846 && attr->children->type==XML_TEXT_NODE
847 && attr->children->content
848 && attr->children->content[0])
850 name = (const char *)attr->children->content;
855 for (attr = ptr_target->properties; attr; attr = attr->next)
856 if (!strcmp((const char *) attr->name, "database"))
859 && attr->children->type==XML_TEXT_NODE
860 && attr->children->content)
861 *backend_db = (const char *) attr->children->content;
870 char *Yaz_ProxyConfig::get_explain_doc(ODR odr, const char *name,
871 const char *db, int *len)
874 xmlNodePtr ptr_target, ptr_explain;
875 if (m_cp->get_explain_ptr(0 /* host */, db, &ptr_target, &ptr_explain))
877 xmlNodePtr ptr2 = xmlCopyNode(ptr_explain, 1);
879 xmlDocPtr doc = xmlNewDoc((const xmlChar *) "1.0");
881 xmlDocSetRootElement(doc, ptr2);
884 xmlDocDumpMemory(doc, &buf_out, len);
885 char *content = (char*) odr_malloc(odr, *len);
886 memcpy(content, buf_out, *len);
896 void Yaz_ProxyConfig::get_target_info(const char *name,
901 int *target_idletime,
902 int *client_idletime,
904 int *keepalive_limit_bw,
905 int *keepalive_limit_pdu,
907 const char **cql2rpn)
911 if (!m_cp->m_proxyPtr)
918 for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
920 if (ptr->type == XML_ELEMENT_NODE &&
921 !strcmp((const char *) ptr->name, "max-clients"))
923 const char *t = m_cp->get_text(ptr);
926 *max_clients = atoi(t);
927 if (*max_clients < 1)
932 ptr = m_cp->find_target_node(name, 0);
940 m_cp->return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
941 target_idletime, client_idletime,
942 keepalive_limit_bw, keepalive_limit_pdu,