1 /* $Id: yaz-proxy-config.cpp,v 1.6 2004-08-29 13:01:43 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,
451 char **backend_charset)
465 xfree (*backend_type);
470 xfree (*backend_charset);
471 *backend_charset = 0;
474 int syntax_has_matched = 0;
477 ptr = m_cp->find_target_node(name, 0);
480 for(ptr = ptr->children; ptr; ptr = ptr->next)
482 if (ptr->type == XML_ELEMENT_NODE &&
483 !strcmp((const char *) ptr->name, "syntax"))
485 int match = 0; // if we match record syntax
486 const char *match_type = 0;
487 const char *match_error = 0;
488 const char *match_marcxml = 0;
489 const char *match_stylesheet = 0;
490 const char *match_identifier = 0;
491 const char *match_backend_type = 0;
492 const char *match_backend_charset = 0;
493 struct _xmlAttr *attr;
494 for (attr = ptr->properties; attr; attr = attr->next)
496 if (!strcmp((const char *) attr->name, "type") &&
497 attr->children && attr->children->type == XML_TEXT_NODE)
498 match_type = (const char *) attr->children->content;
499 if (!strcmp((const char *) attr->name, "error") &&
500 attr->children && attr->children->type == XML_TEXT_NODE)
501 match_error = (const char *) attr->children->content;
502 if (!strcmp((const char *) attr->name, "marcxml") &&
503 attr->children && attr->children->type == XML_TEXT_NODE)
504 match_marcxml = (const char *) attr->children->content;
505 if (!strcmp((const char *) attr->name, "stylesheet") &&
506 attr->children && attr->children->type == XML_TEXT_NODE)
507 match_stylesheet = (const char *) attr->children->content;
508 if (!strcmp((const char *) attr->name, "identifier") &&
509 attr->children && attr->children->type == XML_TEXT_NODE)
510 match_identifier = (const char *) attr->children->content;
511 if (!strcmp((const char *) attr->name, "backendtype") &&
512 attr->children && attr->children->type == XML_TEXT_NODE)
513 match_backend_type = (const char *)
514 attr->children->content;
515 if (!strcmp((const char *) attr->name, "backendcharset") &&
516 attr->children && attr->children->type == XML_TEXT_NODE)
517 match_backend_charset = (const char *)
518 attr->children->content;
522 if (!strcmp(match_type, "*"))
524 else if (!strcmp(match_type, "none"))
531 int match_oid[OID_SIZE];
532 oid_name_to_oid(CLASS_RECSYN, match_type, match_oid);
533 if (oid_oidcmp(match_oid, syntax) == 0)
540 syntax_has_matched = 1;
541 match = m_cp->check_schema(ptr->children, comp,
546 if (stylesheet && match_stylesheet)
549 *stylesheet = xstrdup(match_stylesheet);
551 if (schema && match_identifier)
554 *schema = xstrdup(match_identifier);
556 if (backend_type && match_backend_type)
558 xfree(*backend_type);
559 *backend_type = xstrdup(match_backend_type);
561 if (backend_charset && match_backend_charset)
563 xfree(*backend_charset);
564 *backend_charset = xstrdup(match_backend_charset);
572 if (syntax_has_matched) // if syntax OK, bad schema/ESN
576 char dotoid_str[100];
577 oid_to_dotstring(syntax, dotoid_str);
578 *addinfo = odr_strdup(odr, dotoid_str);
580 return atoi(match_error);
591 xmlNodePtr Yaz_ProxyConfigP::find_target_db(xmlNodePtr ptr, const char *db)
598 for (dptr = ptr->children; dptr; dptr = dptr->next)
599 if (dptr->type == XML_ELEMENT_NODE &&
600 !strcmp((const char *) dptr->name, "database"))
602 struct _xmlAttr *attr;
603 for (attr = dptr->properties; attr; attr = attr->next)
604 if (!strcmp((const char *) attr->name, "name"))
607 && attr->children->type==XML_TEXT_NODE
608 && attr->children->content
609 && (!strcmp((const char *) attr->children->content, db)
610 || !strcmp((const char *) attr->children->content,
618 xmlNodePtr Yaz_ProxyConfigP::find_target_node(const char *name, const char *db)
623 for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
625 if (ptr->type == XML_ELEMENT_NODE &&
626 !strcmp((const char *) ptr->name, "target"))
631 // <target default="1"> ?
632 struct _xmlAttr *attr;
633 for (attr = ptr->properties; attr; attr = attr->next)
634 if (!strcmp((const char *) attr->name, "default") &&
635 attr->children && attr->children->type == XML_TEXT_NODE)
637 xmlChar *t = attr->children->content;
640 return find_target_db(ptr, db);
646 // <target name="name"> ?
647 struct _xmlAttr *attr;
648 for (attr = ptr->properties; attr; attr = attr->next)
649 if (!strcmp((const char *) attr->name, "name"))
652 && attr->children->type==XML_TEXT_NODE
653 && attr->children->content
654 && (!strcmp((const char *) attr->children->content,
656 || !strcmp((const char *) attr->children->content,
659 return find_target_db(ptr, db);
669 int Yaz_ProxyConfig::get_target_no(int no,
675 int *target_idletime,
676 int *client_idletime,
678 int *keepalive_limit_bw,
679 int *keepalive_limit_pdu,
681 const char **cql2rpn)
685 if (!m_cp->m_proxyPtr)
688 for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
689 if (ptr->type == XML_ELEMENT_NODE &&
690 !strcmp((const char *) ptr->name, "target"))
694 struct _xmlAttr *attr;
695 for (attr = ptr->properties; attr; attr = attr->next)
696 if (!strcmp((const char *) attr->name, "name"))
699 && attr->children->type==XML_TEXT_NODE
700 && attr->children->content)
701 *name = (const char *) attr->children->content;
703 m_cp->return_target_info(
705 limit_bw, limit_pdu, limit_req,
706 target_idletime, client_idletime,
707 keepalive_limit_bw, keepalive_limit_pdu,
717 int Yaz_ProxyConfigP::mycmp(const char *hay, const char *item, size_t len)
719 if (len == strlen(item) && memcmp(hay, item, len) == 0)
724 void Yaz_ProxyConfig::get_generic_info(int *log_mask,
729 if (!m_cp->m_proxyPtr)
731 for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
733 if (ptr->type == XML_ELEMENT_NODE
734 && !strcmp((const char *) ptr->name, "log"))
736 const char *v = m_cp->get_text(ptr);
741 while (*cp && *cp != ',' && !isspace(*cp))
744 if (m_cp->mycmp(v, "client-apdu", len))
745 *log_mask |= PROXY_LOG_APDU_CLIENT;
746 if (m_cp->mycmp(v, "server-apdu", len))
747 *log_mask |= PROXY_LOG_APDU_SERVER;
748 if (m_cp->mycmp(v, "client-requests", len))
749 *log_mask |= PROXY_LOG_REQ_CLIENT;
750 if (m_cp->mycmp(v, "server-requests", len))
751 *log_mask |= PROXY_LOG_REQ_SERVER;
753 *log_mask |= atoi(v);
756 while (*cp && isspace(*cp))
761 if (ptr->type == XML_ELEMENT_NODE &&
762 !strcmp((const char *) ptr->name, "max-clients"))
764 const char *t = m_cp->get_text(ptr);
767 *max_clients = atoi(t);
768 if (*max_clients < 1)
776 char *Yaz_ProxyConfig::get_explain(ODR odr, const char *name, const char *db,
780 xmlNodePtr ptr = m_cp->find_target_node(name, db);
784 for (; ptr; ptr = ptr->next)
785 if (ptr->type == XML_ELEMENT_NODE &&
786 !strcmp((const char *) ptr->name, "explain"))
788 xmlNodePtr ptr1 = ptr->children;
791 for (; ptr1; ptr1 = ptr1->next)
792 if (ptr1->type == XML_ELEMENT_NODE &&
793 !strcmp((const char *) ptr1->name, "serverInfo"))
797 for (ptr1 = ptr1->children; ptr1; ptr1 = ptr1->next)
798 if (ptr1->type == XML_ELEMENT_NODE &&
799 !strcmp((const char *) ptr1->name, "database"))
804 for (ptr1 = ptr1->children; ptr1; ptr1 = ptr1->next)
805 if (ptr1->type == XML_TEXT_NODE &&
807 !strcmp((const char *) ptr1->content, db))
812 xmlNodePtr ptr2 = xmlCopyNode(ptr, 1);
814 xmlDocPtr doc = xmlNewDoc((const xmlChar *) "1.0");
816 xmlDocSetRootElement(doc, ptr2);
819 xmlDocDumpMemory(doc, &buf_out, len);
820 char *content = (char*) odr_malloc(odr, *len);
821 memcpy(content, buf_out, *len);
832 void Yaz_ProxyConfig::get_target_info(const char *name,
837 int *target_idletime,
838 int *client_idletime,
840 int *keepalive_limit_bw,
841 int *keepalive_limit_pdu,
843 const char **cql2rpn)
847 if (!m_cp->m_proxyPtr)
854 for (ptr = m_cp->m_proxyPtr->children; ptr; ptr = ptr->next)
856 if (ptr->type == XML_ELEMENT_NODE &&
857 !strcmp((const char *) ptr->name, "max-clients"))
859 const char *t = m_cp->get_text(ptr);
862 *max_clients = atoi(t);
863 if (*max_clients < 1)
868 ptr = m_cp->find_target_node(name, 0);
876 m_cp->return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
877 target_idletime, client_idletime,
878 keepalive_limit_bw, keepalive_limit_pdu,