1 /* $Id: yaz-proxy-config.cpp,v 1.5 2004-08-10 09:02:16 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,
66 Yaz_ProxyConfig::Yaz_ProxyConfig()
68 m_cp = new Yaz_ProxyConfigP;
76 Yaz_ProxyConfig::~Yaz_ProxyConfig()
79 if (!m_cp->m_copy && m_cp->m_docPtr)
80 xmlFreeDoc(m_cp->m_docPtr);
85 int Yaz_ProxyConfig::read_xml(const char *fname)
88 xmlDocPtr ndoc = xmlParseFile(fname);
92 yaz_log(LOG_WARN, "Config file %s not found or parse error", fname);
95 xmlNodePtr proxyPtr = xmlDocGetRootElement(ndoc);
96 if (!proxyPtr || proxyPtr->type != XML_ELEMENT_NODE ||
97 strcmp((const char *) proxyPtr->name, "proxy"))
99 yaz_log(LOG_WARN, "No proxy element in %s", fname);
103 m_cp->m_proxyPtr = proxyPtr;
105 // OK: release previous and make it the current one.
107 xmlFreeDoc(m_cp->m_docPtr);
108 m_cp->m_docPtr = ndoc;
116 const char *Yaz_ProxyConfigP::get_text(xmlNodePtr ptr)
118 for(ptr = ptr->children; ptr; ptr = ptr->next)
119 if (ptr->type == XML_TEXT_NODE)
121 xmlChar *t = ptr->content;
126 return (const char *) t;
134 void Yaz_ProxyConfigP::return_limit(xmlNodePtr ptr,
139 for (ptr = ptr->children; ptr; ptr = ptr->next)
141 if (ptr->type == XML_ELEMENT_NODE
142 && !strcmp((const char *) ptr->name, "bandwidth"))
144 const char *t = get_text(ptr);
148 if (ptr->type == XML_ELEMENT_NODE
149 && !strcmp((const char *) ptr->name, "retrieve"))
151 const char *t = get_text(ptr);
153 *limit_req = atoi(t);
155 if (ptr->type == XML_ELEMENT_NODE
156 && !strcmp((const char *) ptr->name, "pdu"))
158 const char *t = get_text(ptr);
160 *limit_pdu = atoi(t);
167 void Yaz_ProxyConfigP::return_target_info(xmlNodePtr ptr,
172 int *target_idletime,
173 int *client_idletime,
174 int *keepalive_limit_bw,
175 int *keepalive_limit_pdu,
177 const char **cql2rpn)
182 for (; ptr; ptr = ptr->next)
184 if (ptr->type == XML_ELEMENT_NODE
185 && !strcmp((const char *) ptr->name, "preinit"))
187 const char *v = get_text(ptr);
188 *pre_init = v ? atoi(v) : 1;
190 if (ptr->type == XML_ELEMENT_NODE
191 && !strcmp((const char *) ptr->name, "url"))
193 const char *t = get_text(ptr);
194 if (t && no_url < MAX_ZURL_PLEX)
200 if (ptr->type == XML_ELEMENT_NODE
201 && !strcmp((const char *) ptr->name, "keepalive"))
204 *keepalive_limit_bw = 500000;
205 *keepalive_limit_pdu = 1000;
206 return_limit(ptr, keepalive_limit_bw, keepalive_limit_pdu,
209 if (ptr->type == XML_ELEMENT_NODE
210 && !strcmp((const char *) ptr->name, "limit"))
211 return_limit(ptr, limit_bw, limit_pdu, limit_req);
212 if (ptr->type == XML_ELEMENT_NODE
213 && !strcmp((const char *) ptr->name, "target-timeout"))
215 const char *t = get_text(ptr);
218 *target_idletime = atoi(t);
219 if (*target_idletime < 0)
220 *target_idletime = 0;
223 if (ptr->type == XML_ELEMENT_NODE
224 && !strcmp((const char *) ptr->name, "client-timeout"))
226 const char *t = get_text(ptr);
229 *client_idletime = atoi(t);
230 if (*client_idletime < 0)
231 *client_idletime = 0;
234 if (ptr->type == XML_ELEMENT_NODE
235 && !strcmp((const char *) ptr->name, "cql2rpn"))
237 const char *t = get_text(ptr);
245 int Yaz_ProxyConfigP::atoi_l(const char **cp)
248 while (**cp && isdigit(**cp))
250 v = v*10 + (**cp - '0');
256 int Yaz_ProxyConfigP::match_list(int v, const char *m)
260 while(*m && isspace(*m))
271 if (v >= l && v <= h)
280 int Yaz_ProxyConfigP::check_type_1_attributes(ODR odr, xmlNodePtr ptrl,
281 Z_AttributeList *attrs,
285 for (i = 0; i<attrs->num_attributes; i++)
287 Z_AttributeElement *el = attrs->attributes[i];
289 if (!el->attributeType)
291 int type = *el->attributeType;
294 if (el->which == Z_AttributeValue_numeric && el->value.numeric)
295 value = el->value.numeric;
298 for(ptr = ptrl->children; ptr; ptr = ptr->next)
300 if (ptr->type == XML_ELEMENT_NODE &&
301 !strcmp((const char *) ptr->name, "attribute"))
303 const char *match_type = 0;
304 const char *match_value = 0;
305 const char *match_error = 0;
306 struct _xmlAttr *attr;
307 for (attr = ptr->properties; attr; attr = attr->next)
309 if (!strcmp((const char *) attr->name, "type") &&
310 attr->children && attr->children->type == XML_TEXT_NODE)
311 match_type = (const char *) attr->children->content;
312 if (!strcmp((const char *) attr->name, "value") &&
313 attr->children && attr->children->type == XML_TEXT_NODE)
314 match_value = (const char *) attr->children->content;
315 if (!strcmp((const char *) attr->name, "error") &&
316 attr->children && attr->children->type == XML_TEXT_NODE)
317 match_error = (const char *) attr->children->content;
319 if (match_type && match_value)
321 char addinfo_str[20];
322 if (!match_list(type, match_type))
326 if (!strcmp(match_type, "*"))
327 sprintf (addinfo_str, "%d", type);
330 if (!match_list(*value, match_value))
332 sprintf (addinfo_str, "%d", *value);
340 *addinfo = odr_strdup(odr, addinfo_str);
341 return atoi(match_error);
353 int Yaz_ProxyConfigP::check_type_1_structure(ODR odr, xmlNodePtr ptr,
357 if (q->which == Z_RPNStructure_complex)
359 int e = check_type_1_structure(odr, ptr, q->u.complex->s1, addinfo);
362 e = check_type_1_structure(odr, ptr, q->u.complex->s2, addinfo);
365 else if (q->which == Z_RPNStructure_simple)
367 if (q->u.simple->which == Z_Operand_APT)
369 return check_type_1_attributes(
370 odr, ptr, q->u.simple->u.attributesPlusTerm->attributes,
379 int Yaz_ProxyConfigP::check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
382 // possibly check for Bib-1
383 return check_type_1_structure(odr, ptr, query->RPNStructure, addinfo);
387 int Yaz_ProxyConfig::check_query(ODR odr, const char *name, Z_Query *query,
393 ptr = m_cp->find_target_node(name, 0);
396 if (query->which == Z_Query_type_1 || query->which == Z_Query_type_101)
397 return m_cp->check_type_1(odr, ptr, query->u.type_1, addinfo);
404 int Yaz_ProxyConfigP::check_schema(xmlNodePtr ptr, Z_RecordComposition *comp,
405 const char *schema_identifier)
408 int default_match = 1;
409 if (comp && comp->which == Z_RecordComp_simple &&
410 comp->u.simple && comp->u.simple->which == Z_ElementSetNames_generic)
412 esn = comp->u.simple->u.generic;
414 // if no ESN/schema was given accept..
417 // check if schema identifier match
418 if (schema_identifier && !strcmp(esn, schema_identifier))
420 // Check each name element
421 for (; ptr; ptr = ptr->next)
423 if (ptr->type == XML_ELEMENT_NODE
424 && !strcmp((const char *) ptr->name, "name"))
426 xmlNodePtr tptr = ptr->children;
428 for (; tptr; tptr = tptr->next)
429 if (tptr->type == XML_TEXT_NODE && tptr->content)
431 xmlChar *t = tptr->content;
432 while (*t && isspace(*t))
435 while (esn[i] && esn[i] == t[i])
437 if (!esn[i] && (!t[i] || isspace(t[i])))
442 return default_match;
446 int Yaz_ProxyConfig::check_syntax(ODR odr, const char *name,
447 Odr_oid *syntax, Z_RecordComposition *comp,
449 char **stylesheet, char **schema,
464 xfree (*backend_type);
468 int syntax_has_matched = 0;
471 ptr = m_cp->find_target_node(name, 0);
474 for(ptr = ptr->children; ptr; ptr = ptr->next)
476 if (ptr->type == XML_ELEMENT_NODE &&
477 !strcmp((const char *) ptr->name, "syntax"))
479 int match = 0; // if we match record syntax
480 const char *match_type = 0;
481 const char *match_error = 0;
482 const char *match_marcxml = 0;
483 const char *match_stylesheet = 0;
484 const char *match_identifier = 0;
485 const char *match_backend_type = 0;
486 struct _xmlAttr *attr;
487 for (attr = ptr->properties; attr; attr = attr->next)
489 if (!strcmp((const char *) attr->name, "type") &&
490 attr->children && attr->children->type == XML_TEXT_NODE)
491 match_type = (const char *) attr->children->content;
492 if (!strcmp((const char *) attr->name, "error") &&
493 attr->children && attr->children->type == XML_TEXT_NODE)
494 match_error = (const char *) attr->children->content;
495 if (!strcmp((const char *) attr->name, "marcxml") &&
496 attr->children && attr->children->type == XML_TEXT_NODE)
497 match_marcxml = (const char *) attr->children->content;
498 if (!strcmp((const char *) attr->name, "stylesheet") &&
499 attr->children && attr->children->type == XML_TEXT_NODE)
500 match_stylesheet = (const char *) attr->children->content;
501 if (!strcmp((const char *) attr->name, "identifier") &&
502 attr->children && attr->children->type == XML_TEXT_NODE)
503 match_identifier = (const char *) attr->children->content;
504 if (!strcmp((const char *) attr->name, "backendtype") &&
505 attr->children && attr->children->type == XML_TEXT_NODE)
506 match_backend_type = (const char *)
507 attr->children->content;
511 if (!strcmp(match_type, "*"))
513 else if (!strcmp(match_type, "none"))
520 int match_oid[OID_SIZE];
521 oid_name_to_oid(CLASS_RECSYN, match_type, match_oid);
522 if (oid_oidcmp(match_oid, syntax) == 0)
529 syntax_has_matched = 1;
530 match = m_cp->check_schema(ptr->children, comp,
535 if (stylesheet && match_stylesheet)
538 *stylesheet = xstrdup(match_stylesheet);
540 if (schema && match_identifier)
543 *schema = xstrdup(match_identifier);
545 if (backend_type && match_backend_type)
547 xfree(*backend_type);
548 *backend_type = xstrdup(match_backend_type);
556 if (syntax_has_matched) // if syntax OK, bad schema/ESN
560 char dotoid_str[100];
561 oid_to_dotstring(syntax, dotoid_str);
562 *addinfo = odr_strdup(odr, dotoid_str);
564 return atoi(match_error);
575 xmlNodePtr Yaz_ProxyConfigP::find_target_db(xmlNodePtr ptr, const char *db)
582 for (dptr = ptr->children; dptr; dptr = dptr->next)
583 if (dptr->type == XML_ELEMENT_NODE &&
584 !strcmp((const char *) dptr->name, "database"))
586 struct _xmlAttr *attr;
587 for (attr = dptr->properties; attr; attr = attr->next)
588 if (!strcmp((const char *) attr->name, "name"))
591 && attr->children->type==XML_TEXT_NODE
592 && attr->children->content
593 && (!strcmp((const char *) attr->children->content, db)
594 || !strcmp((const char *) attr->children->content,
602 xmlNodePtr Yaz_ProxyConfigP::find_target_node(const char *name, const char *db)
607 for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
609 if (ptr->type == XML_ELEMENT_NODE &&
610 !strcmp((const char *) ptr->name, "target"))
615 // <target default="1"> ?
616 struct _xmlAttr *attr;
617 for (attr = ptr->properties; attr; attr = attr->next)
618 if (!strcmp((const char *) attr->name, "default") &&
619 attr->children && attr->children->type == XML_TEXT_NODE)
621 xmlChar *t = attr->children->content;
624 return find_target_db(ptr, db);
630 // <target name="name"> ?
631 struct _xmlAttr *attr;
632 for (attr = ptr->properties; attr; attr = attr->next)
633 if (!strcmp((const char *) attr->name, "name"))
636 && attr->children->type==XML_TEXT_NODE
637 && attr->children->content
638 && (!strcmp((const char *) attr->children->content,
640 || !strcmp((const char *) attr->children->content,
643 return find_target_db(ptr, db);
653 int Yaz_ProxyConfig::get_target_no(int no,
659 int *target_idletime,
660 int *client_idletime,
662 int *keepalive_limit_bw,
663 int *keepalive_limit_pdu,
665 const char **cql2rpn)
669 if (!m_cp->m_proxyPtr)
672 for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
673 if (ptr->type == XML_ELEMENT_NODE &&
674 !strcmp((const char *) ptr->name, "target"))
678 struct _xmlAttr *attr;
679 for (attr = ptr->properties; attr; attr = attr->next)
680 if (!strcmp((const char *) attr->name, "name"))
683 && attr->children->type==XML_TEXT_NODE
684 && attr->children->content)
685 *name = (const char *) attr->children->content;
687 m_cp->return_target_info(
689 limit_bw, limit_pdu, limit_req,
690 target_idletime, client_idletime,
691 keepalive_limit_bw, keepalive_limit_pdu,
701 int Yaz_ProxyConfigP::mycmp(const char *hay, const char *item, size_t len)
703 if (len == strlen(item) && memcmp(hay, item, len) == 0)
708 void Yaz_ProxyConfig::get_generic_info(int *log_mask,
713 if (!m_cp->m_proxyPtr)
715 for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
717 if (ptr->type == XML_ELEMENT_NODE
718 && !strcmp((const char *) ptr->name, "log"))
720 const char *v = m_cp->get_text(ptr);
725 while (*cp && *cp != ',' && !isspace(*cp))
728 if (m_cp->mycmp(v, "client-apdu", len))
729 *log_mask |= PROXY_LOG_APDU_CLIENT;
730 if (m_cp->mycmp(v, "server-apdu", len))
731 *log_mask |= PROXY_LOG_APDU_SERVER;
732 if (m_cp->mycmp(v, "client-requests", len))
733 *log_mask |= PROXY_LOG_REQ_CLIENT;
734 if (m_cp->mycmp(v, "server-requests", len))
735 *log_mask |= PROXY_LOG_REQ_SERVER;
737 *log_mask |= atoi(v);
740 while (*cp && isspace(*cp))
745 if (ptr->type == XML_ELEMENT_NODE &&
746 !strcmp((const char *) ptr->name, "max-clients"))
748 const char *t = m_cp->get_text(ptr);
751 *max_clients = atoi(t);
752 if (*max_clients < 1)
760 char *Yaz_ProxyConfig::get_explain(ODR odr, const char *name, const char *db,
764 xmlNodePtr ptr = m_cp->find_target_node(name, db);
768 for (; ptr; ptr = ptr->next)
769 if (ptr->type == XML_ELEMENT_NODE &&
770 !strcmp((const char *) ptr->name, "explain"))
772 xmlNodePtr ptr1 = ptr->children;
775 for (; ptr1; ptr1 = ptr1->next)
776 if (ptr1->type == XML_ELEMENT_NODE &&
777 !strcmp((const char *) ptr1->name, "serverInfo"))
781 for (ptr1 = ptr1->children; ptr1; ptr1 = ptr1->next)
782 if (ptr1->type == XML_ELEMENT_NODE &&
783 !strcmp((const char *) ptr1->name, "database"))
788 for (ptr1 = ptr1->children; ptr1; ptr1 = ptr1->next)
789 if (ptr1->type == XML_TEXT_NODE &&
791 !strcmp((const char *) ptr1->content, db))
796 xmlNodePtr ptr2 = xmlCopyNode(ptr, 1);
798 xmlDocPtr doc = xmlNewDoc((const xmlChar *) "1.0");
800 xmlDocSetRootElement(doc, ptr2);
803 xmlDocDumpMemory(doc, &buf_out, len);
804 char *content = (char*) odr_malloc(odr, *len);
805 memcpy(content, buf_out, *len);
816 void Yaz_ProxyConfig::get_target_info(const char *name,
821 int *target_idletime,
822 int *client_idletime,
824 int *keepalive_limit_bw,
825 int *keepalive_limit_pdu,
827 const char **cql2rpn)
831 if (!m_cp->m_proxyPtr)
838 for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
840 if (ptr->type == XML_ELEMENT_NODE &&
841 !strcmp((const char *) ptr->name, "max-clients"))
843 const char *t = m_cp->get_text(ptr);
846 *max_clients = atoi(t);
847 if (*max_clients < 1)
852 ptr = m_cp->find_target_node(name, 0);
860 m_cp->return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
861 target_idletime, client_idletime,
862 keepalive_limit_bw, keepalive_limit_pdu,