1 /* $Id: yaz-proxy-config.cpp,v 1.4 2004-04-22 07:46:21 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)
462 int syntax_has_matched = 0;
465 ptr = m_cp->find_target_node(name, 0);
468 for(ptr = ptr->children; ptr; ptr = ptr->next)
470 if (ptr->type == XML_ELEMENT_NODE &&
471 !strcmp((const char *) ptr->name, "syntax"))
473 int match = 0; // if we match record syntax
474 const char *match_type = 0;
475 const char *match_error = 0;
476 const char *match_marcxml = 0;
477 const char *match_stylesheet = 0;
478 const char *match_identifier = 0;
479 struct _xmlAttr *attr;
480 for (attr = ptr->properties; attr; attr = attr->next)
482 if (!strcmp((const char *) attr->name, "type") &&
483 attr->children && attr->children->type == XML_TEXT_NODE)
484 match_type = (const char *) attr->children->content;
485 if (!strcmp((const char *) attr->name, "error") &&
486 attr->children && attr->children->type == XML_TEXT_NODE)
487 match_error = (const char *) attr->children->content;
488 if (!strcmp((const char *) attr->name, "marcxml") &&
489 attr->children && attr->children->type == XML_TEXT_NODE)
490 match_marcxml = (const char *) attr->children->content;
491 if (!strcmp((const char *) attr->name, "stylesheet") &&
492 attr->children && attr->children->type == XML_TEXT_NODE)
493 match_stylesheet = (const char *) attr->children->content;
494 if (!strcmp((const char *) attr->name, "identifier") &&
495 attr->children && attr->children->type == XML_TEXT_NODE)
496 match_identifier = (const char *) attr->children->content;
500 if (!strcmp(match_type, "*"))
502 else if (!strcmp(match_type, "none"))
509 int match_oid[OID_SIZE];
510 oid_name_to_oid(CLASS_RECSYN, match_type, match_oid);
511 if (oid_oidcmp(match_oid, syntax) == 0)
518 syntax_has_matched = 1;
519 match = m_cp->check_schema(ptr->children, comp,
524 if (stylesheet && match_stylesheet)
527 *stylesheet = xstrdup(match_stylesheet);
529 if (schema && match_identifier)
532 *schema = xstrdup(match_identifier);
540 if (syntax_has_matched) // if syntax OK, bad schema/ESN
544 char dotoid_str[100];
545 oid_to_dotstring(syntax, dotoid_str);
546 *addinfo = odr_strdup(odr, dotoid_str);
548 return atoi(match_error);
559 xmlNodePtr Yaz_ProxyConfigP::find_target_db(xmlNodePtr ptr, const char *db)
566 for (dptr = ptr->children; dptr; dptr = dptr->next)
567 if (dptr->type == XML_ELEMENT_NODE &&
568 !strcmp((const char *) dptr->name, "database"))
570 struct _xmlAttr *attr;
571 for (attr = dptr->properties; attr; attr = attr->next)
572 if (!strcmp((const char *) attr->name, "name"))
575 && attr->children->type==XML_TEXT_NODE
576 && attr->children->content
577 && (!strcmp((const char *) attr->children->content, db)
578 || !strcmp((const char *) attr->children->content,
586 xmlNodePtr Yaz_ProxyConfigP::find_target_node(const char *name, const char *db)
591 for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
593 if (ptr->type == XML_ELEMENT_NODE &&
594 !strcmp((const char *) ptr->name, "target"))
599 // <target default="1"> ?
600 struct _xmlAttr *attr;
601 for (attr = ptr->properties; attr; attr = attr->next)
602 if (!strcmp((const char *) attr->name, "default") &&
603 attr->children && attr->children->type == XML_TEXT_NODE)
605 xmlChar *t = attr->children->content;
608 return find_target_db(ptr, db);
614 // <target name="name"> ?
615 struct _xmlAttr *attr;
616 for (attr = ptr->properties; attr; attr = attr->next)
617 if (!strcmp((const char *) attr->name, "name"))
620 && attr->children->type==XML_TEXT_NODE
621 && attr->children->content
622 && (!strcmp((const char *) attr->children->content,
624 || !strcmp((const char *) attr->children->content,
627 return find_target_db(ptr, db);
637 int Yaz_ProxyConfig::get_target_no(int no,
643 int *target_idletime,
644 int *client_idletime,
646 int *keepalive_limit_bw,
647 int *keepalive_limit_pdu,
649 const char **cql2rpn)
653 if (!m_cp->m_proxyPtr)
656 for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
657 if (ptr->type == XML_ELEMENT_NODE &&
658 !strcmp((const char *) ptr->name, "target"))
662 struct _xmlAttr *attr;
663 for (attr = ptr->properties; attr; attr = attr->next)
664 if (!strcmp((const char *) attr->name, "name"))
667 && attr->children->type==XML_TEXT_NODE
668 && attr->children->content)
669 *name = (const char *) attr->children->content;
671 m_cp->return_target_info(
673 limit_bw, limit_pdu, limit_req,
674 target_idletime, client_idletime,
675 keepalive_limit_bw, keepalive_limit_pdu,
685 int Yaz_ProxyConfigP::mycmp(const char *hay, const char *item, size_t len)
687 if (len == strlen(item) && memcmp(hay, item, len) == 0)
692 void Yaz_ProxyConfig::get_generic_info(int *log_mask,
697 if (!m_cp->m_proxyPtr)
699 for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
701 if (ptr->type == XML_ELEMENT_NODE
702 && !strcmp((const char *) ptr->name, "log"))
704 const char *v = m_cp->get_text(ptr);
709 while (*cp && *cp != ',' && !isspace(*cp))
712 if (m_cp->mycmp(v, "client-apdu", len))
713 *log_mask |= PROXY_LOG_APDU_CLIENT;
714 if (m_cp->mycmp(v, "server-apdu", len))
715 *log_mask |= PROXY_LOG_APDU_SERVER;
716 if (m_cp->mycmp(v, "client-requests", len))
717 *log_mask |= PROXY_LOG_REQ_CLIENT;
718 if (m_cp->mycmp(v, "server-requests", len))
719 *log_mask |= PROXY_LOG_REQ_SERVER;
721 *log_mask |= atoi(v);
724 while (*cp && isspace(*cp))
729 if (ptr->type == XML_ELEMENT_NODE &&
730 !strcmp((const char *) ptr->name, "max-clients"))
732 const char *t = m_cp->get_text(ptr);
735 *max_clients = atoi(t);
736 if (*max_clients < 1)
744 char *Yaz_ProxyConfig::get_explain(ODR odr, const char *name, const char *db,
748 xmlNodePtr ptr = m_cp->find_target_node(name, db);
752 for (; ptr; ptr = ptr->next)
753 if (ptr->type == XML_ELEMENT_NODE &&
754 !strcmp((const char *) ptr->name, "explain"))
756 xmlNodePtr ptr1 = ptr->children;
759 for (; ptr1; ptr1 = ptr1->next)
760 if (ptr1->type == XML_ELEMENT_NODE &&
761 !strcmp((const char *) ptr1->name, "serverInfo"))
765 for (ptr1 = ptr1->children; ptr1; ptr1 = ptr1->next)
766 if (ptr1->type == XML_ELEMENT_NODE &&
767 !strcmp((const char *) ptr1->name, "database"))
772 for (ptr1 = ptr1->children; ptr1; ptr1 = ptr1->next)
773 if (ptr1->type == XML_TEXT_NODE &&
775 !strcmp((const char *) ptr1->content, db))
780 xmlNodePtr ptr2 = xmlCopyNode(ptr, 1);
782 xmlDocPtr doc = xmlNewDoc((const xmlChar *) "1.0");
784 xmlDocSetRootElement(doc, ptr2);
787 xmlDocDumpMemory(doc, &buf_out, len);
788 char *content = (char*) odr_malloc(odr, *len);
789 memcpy(content, buf_out, *len);
800 void Yaz_ProxyConfig::get_target_info(const char *name,
805 int *target_idletime,
806 int *client_idletime,
808 int *keepalive_limit_bw,
809 int *keepalive_limit_pdu,
811 const char **cql2rpn)
815 if (!m_cp->m_proxyPtr)
822 for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
824 if (ptr->type == XML_ELEMENT_NODE &&
825 !strcmp((const char *) ptr->name, "max-clients"))
827 const char *t = m_cp->get_text(ptr);
830 *max_clients = atoi(t);
831 if (*max_clients < 1)
836 ptr = m_cp->find_target_node(name, 0);
844 m_cp->return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
845 target_idletime, client_idletime,
846 keepalive_limit_bw, keepalive_limit_pdu,