b824462e17b4f21286d853743835b0092f1407bf
[yazpp-moved-to-github.git] / src / yaz-proxy-config.cpp
1 /*
2  * Copyright (c) 1998-2003, Index Data.
3  * See the file LICENSE for details.
4  * 
5  * $Id: yaz-proxy-config.cpp,v 1.16 2003-12-20 22:44:30 adam Exp $
6  */
7
8 #include <ctype.h>
9 #include <yaz/log.h>
10 #include <yaz++/proxy.h>
11
12 Yaz_ProxyConfig::Yaz_ProxyConfig()
13 {
14     m_copy = 0;
15 #if HAVE_XML2
16     m_docPtr = 0;
17     m_proxyPtr = 0;
18 #endif
19 }
20
21 Yaz_ProxyConfig::~Yaz_ProxyConfig()
22 {
23 #if HAVE_XML2
24     if (!m_copy && m_docPtr)
25         xmlFreeDoc(m_docPtr);
26 #endif
27 }
28
29 int Yaz_ProxyConfig::read_xml(const char *fname)
30 {
31 #if HAVE_XML2
32     xmlDocPtr ndoc = xmlParseFile(fname);
33
34     if (!ndoc)
35     {
36         yaz_log(LOG_WARN, "Config file %s not found or parse error", fname);
37         return -1;  // no good
38     }
39     xmlNodePtr proxyPtr = xmlDocGetRootElement(ndoc);
40     if (!proxyPtr || proxyPtr->type != XML_ELEMENT_NODE ||
41         strcmp((const char *) proxyPtr->name, "proxy"))
42     {
43         yaz_log(LOG_WARN, "No proxy element in %s", fname);
44         xmlFreeDoc(ndoc);
45         return -1;
46     }
47     m_proxyPtr = proxyPtr;
48
49     // OK: release previous and make it the current one.
50     if (m_docPtr)
51         xmlFreeDoc(m_docPtr);
52     m_docPtr = ndoc;
53     return 0;
54 #else
55     return -2;
56 #endif
57 }
58
59 #if HAVE_XML2
60 const char *Yaz_ProxyConfig::get_text(xmlNodePtr ptr)
61 {
62     for(ptr = ptr->children; ptr; ptr = ptr->next)
63         if (ptr->type == XML_TEXT_NODE)
64         {
65             xmlChar *t = ptr->content;
66             if (t)
67             {
68                 while (*t == ' ')
69                     t++;
70                 return (const char *) t;
71             }
72         }
73     return 0;
74 }
75 #endif
76
77 #if HAVE_XML2
78 void Yaz_ProxyConfig::return_limit(xmlNodePtr ptr,
79                                    int *limit_bw,
80                                    int *limit_pdu,
81                                    int *limit_req)
82 {
83     for (ptr = ptr->children; ptr; ptr = ptr->next)
84     {
85         if (ptr->type == XML_ELEMENT_NODE 
86             && !strcmp((const char *) ptr->name, "bandwidth"))
87         {
88             const char *t = get_text(ptr);
89             if (t)
90                 *limit_bw = atoi(t);
91         }
92         if (ptr->type == XML_ELEMENT_NODE 
93             && !strcmp((const char *) ptr->name, "retrieve"))
94         {
95             const char *t = get_text(ptr);
96             if (t)
97                 *limit_req = atoi(t);
98         }
99         if (ptr->type == XML_ELEMENT_NODE 
100             && !strcmp((const char *) ptr->name, "pdu"))
101         {
102             const char *t = get_text(ptr);
103             if (t)
104                 *limit_pdu = atoi(t);
105         }
106     }
107 }
108 #endif
109
110 #if HAVE_XML2
111 void Yaz_ProxyConfig::return_target_info(xmlNodePtr ptr,
112                                          const char **url,
113                                          int *limit_bw,
114                                          int *limit_pdu,
115                                          int *limit_req,
116                                          int *target_idletime,
117                                          int *client_idletime,
118                                          int *keepalive_limit_bw,
119                                          int *keepalive_limit_pdu,
120                                          int *pre_init,
121                                          const char **cql2rpn,
122                                          const char **zeerex)
123 {
124     *pre_init = 0;
125     int no_url = 0;
126     ptr = ptr->children;
127     for (; ptr; ptr = ptr->next)
128     {
129         if (ptr->type == XML_ELEMENT_NODE 
130             && !strcmp((const char *) ptr->name, "preinit"))
131         {
132             const char *v = get_text(ptr);
133             *pre_init = v ? atoi(v) : 1;
134         }
135         if (ptr->type == XML_ELEMENT_NODE 
136             && !strcmp((const char *) ptr->name, "url"))
137         {
138             const char *t = get_text(ptr);
139             if (t && no_url < MAX_ZURL_PLEX)
140             {
141                 url[no_url++] = t;
142                 url[no_url] = 0;
143             }
144         }
145         if (ptr->type == XML_ELEMENT_NODE 
146             && !strcmp((const char *) ptr->name, "keepalive"))
147         {
148             int dummy;
149             *keepalive_limit_bw = 500000;
150             *keepalive_limit_pdu = 1000;
151             return_limit(ptr, keepalive_limit_bw, keepalive_limit_pdu,
152                          &dummy);
153         }
154         if (ptr->type == XML_ELEMENT_NODE 
155             && !strcmp((const char *) ptr->name, "limit"))
156             return_limit(ptr, limit_bw, limit_pdu, limit_req);
157         if (ptr->type == XML_ELEMENT_NODE 
158             && !strcmp((const char *) ptr->name, "target-timeout"))
159         {
160             const char *t = get_text(ptr);
161             if (t)
162             {
163                 *target_idletime = atoi(t);
164                 if (*target_idletime < 0)
165                     *target_idletime = 0;
166             }
167         }
168         if (ptr->type == XML_ELEMENT_NODE 
169             && !strcmp((const char *) ptr->name, "client-timeout"))
170         {
171             const char *t = get_text(ptr);
172             if (t)
173             {
174                 *client_idletime = atoi(t);
175                 if (*client_idletime < 0)
176                     *client_idletime = 0;
177             }
178         }
179         if (ptr->type == XML_ELEMENT_NODE 
180             && !strcmp((const char *) ptr->name, "cql2rpn"))
181         {
182             const char *t = get_text(ptr);
183             if (t)
184                 *cql2rpn = t;
185         }
186         if (ptr->type == XML_ELEMENT_NODE 
187             && !strcmp((const char *) ptr->name, "zeerex"))
188         {
189             const char *t = get_text(ptr);
190             if (t)
191                 *zeerex = t;
192         }
193     }
194 }
195 #endif
196
197 int Yaz_ProxyConfig::atoi_l(const char **cp)
198 {
199     int v = 0;
200     while (**cp && isdigit(**cp))
201     {
202         v = v*10 + (**cp - '0');
203         (*cp)++;
204     }
205     return v;
206 }
207
208 int Yaz_ProxyConfig::match_list(int v, const char *m)
209 {
210   while(m && *m)
211   {
212       while(*m && isspace(*m))
213           m++;
214       if (*m == '*')
215           return 1;
216       int l = atoi_l(&m);
217       int h = l;
218       if (*m == '-')
219       {
220           ++m;
221           h = atoi_l(&m);
222       }
223       if (v >= l && v <= h)
224           return 1;
225       if (*m == ',')
226           m++;
227   }
228   return 0;
229 }
230
231 #if HAVE_XML2
232 int Yaz_ProxyConfig::check_type_1_attributes(ODR odr, xmlNodePtr ptrl,
233                                              Z_AttributeList *attrs,
234                                              char **addinfo)
235 {
236     int i;
237     for (i = 0; i<attrs->num_attributes; i++)
238     {
239         Z_AttributeElement *el = attrs->attributes[i];
240         
241         if (!el->attributeType)
242             continue;
243         int type = *el->attributeType;
244         int *value = 0;
245         
246         if (el->which == Z_AttributeValue_numeric && el->value.numeric)
247             value = el->value.numeric;
248         
249         xmlNodePtr ptr;
250         for(ptr = ptrl->children; ptr; ptr = ptr->next)
251         {
252             if (ptr->type == XML_ELEMENT_NODE &&
253                 !strcmp((const char *) ptr->name, "attribute"))
254             {
255                 const char *match_type = 0;
256                 const char *match_value = 0;
257                 const char *match_error = 0;
258                 struct _xmlAttr *attr;
259                 for (attr = ptr->properties; attr; attr = attr->next)
260                 {
261                     if (!strcmp((const char *) attr->name, "type") &&
262                         attr->children && attr->children->type == XML_TEXT_NODE)
263                         match_type = (const char *) attr->children->content;
264                     if (!strcmp((const char *) attr->name, "value") &&
265                         attr->children && attr->children->type == XML_TEXT_NODE)
266                         match_value = (const char *) attr->children->content;
267                     if (!strcmp((const char *) attr->name, "error") &&
268                         attr->children && attr->children->type == XML_TEXT_NODE)
269                         match_error = (const char *) attr->children->content;
270                 }
271                 if (match_type && match_value)
272                 {
273                     char addinfo_str[20];
274                     if (!match_list(type, match_type))
275                         continue;
276                     
277                     *addinfo_str = '\0';
278                     if (!strcmp(match_type, "*"))
279                         sprintf (addinfo_str, "%d", type);
280                     else if (value)
281                     {
282                         if (!match_list(*value, match_value))
283                             continue;
284                         sprintf (addinfo_str, "%d", *value);
285                     }
286                     else
287                         continue;
288                     
289                     if (match_error)
290                     {
291                         if (*addinfo_str)
292                             *addinfo = odr_strdup(odr, addinfo_str);
293                         return atoi(match_error);
294                     }
295                     break;
296                 }
297             }
298         }
299     }
300     return 0;
301 }
302 #endif
303
304 #if HAVE_XML2
305 int Yaz_ProxyConfig::check_type_1_structure(ODR odr, xmlNodePtr ptr,
306                                             Z_RPNStructure *q,
307                                             char **addinfo)
308 {
309     if (q->which == Z_RPNStructure_complex)
310     {
311         int e = check_type_1_structure(odr, ptr, q->u.complex->s1, addinfo);
312         if (e)
313             return e;
314         e = check_type_1_structure(odr, ptr, q->u.complex->s2, addinfo);
315         return e;
316     }
317     else if (q->which == Z_RPNStructure_simple)
318     {
319         if (q->u.simple->which == Z_Operand_APT)
320         {
321             return check_type_1_attributes(
322                 odr, ptr, q->u.simple->u.attributesPlusTerm->attributes,
323                 addinfo);
324         }
325     }
326     return 0;
327 }
328 #endif
329
330 #if HAVE_XML2
331 int Yaz_ProxyConfig::check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
332                                   char **addinfo)
333 {
334     // possibly check for Bib-1
335     return check_type_1_structure(odr, ptr, query->RPNStructure, addinfo);
336 }
337 #endif
338
339 int Yaz_ProxyConfig::check_query(ODR odr, const char *name, Z_Query *query,
340                                  char **addinfo)
341 {
342 #if HAVE_XML2
343     xmlNodePtr ptr;
344     
345     ptr = find_target_node(name);
346     if (ptr)
347     {
348         if (query->which == Z_Query_type_1 || query->which == Z_Query_type_101)
349             return check_type_1(odr, ptr, query->u.type_1, addinfo);
350     }
351 #endif
352     return 0;
353 }
354
355 int Yaz_ProxyConfig::check_syntax(ODR odr, const char *name,
356                                   Odr_oid *syntax, char **addinfo)
357 {
358 #if HAVE_XML2
359     xmlNodePtr ptr;
360     
361     ptr = find_target_node(name);
362     if (!ptr)
363         return 0;
364     for(ptr = ptr->children; ptr; ptr = ptr->next)
365     {
366         if (ptr->type == XML_ELEMENT_NODE &&
367             !strcmp((const char *) ptr->name, "syntax"))
368         {
369             int match = 0;  // if we match record syntax
370             const char *match_type = 0;
371             const char *match_error = 0;
372             const char *match_marcxml = 0;
373             struct _xmlAttr *attr;
374             for (attr = ptr->properties; attr; attr = attr->next)
375             {
376                 if (!strcmp((const char *) attr->name, "type") &&
377                     attr->children && attr->children->type == XML_TEXT_NODE)
378                     match_type = (const char *) attr->children->content;
379                 if (!strcmp((const char *) attr->name, "error") &&
380                     attr->children && attr->children->type == XML_TEXT_NODE)
381                     match_error = (const char *) attr->children->content;
382                 if (!strcmp((const char *) attr->name, "marcxml") &&
383                     attr->children && attr->children->type == XML_TEXT_NODE)
384                     match_marcxml = (const char *) attr->children->content;
385             }
386             if (match_type)
387             {
388                 if (!strcmp(match_type, "*"))
389                     match = 1;
390                 else if (!strcmp(match_type, "none"))
391                 {
392                     if (syntax == 0)
393                         match = 1;
394                 }
395                 else if (syntax)
396                 {
397                     int match_oid[OID_SIZE];
398                     oid_name_to_oid(CLASS_RECSYN, match_type, match_oid);
399                     if (oid_oidcmp(match_oid, syntax) == 0)
400                         match = 1;
401                 }
402             }
403             if (match)
404             {
405                 if (match_marcxml)
406                 {
407                     return -1;
408                 }
409                 if (match_error)
410                 {
411                     if (syntax)
412                     {
413                         char dotoid_str[100];
414                         oid_to_dotstring(syntax, dotoid_str);
415                         *addinfo = odr_strdup(odr, dotoid_str);
416                     }
417                     return atoi(match_error);
418                 }
419                 return 0;
420             }
421         }
422     }
423 #endif
424     return 0;
425 }
426
427 #if HAVE_XML2
428 xmlNodePtr Yaz_ProxyConfig::find_target_node(const char *name)
429 {
430     xmlNodePtr ptr;
431     if (!m_proxyPtr)
432         return 0;
433     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
434     {
435         if (ptr->type == XML_ELEMENT_NODE &&
436             !strcmp((const char *) ptr->name, "target"))
437         {
438             // default one ? 
439             if (!name)
440             {
441                 // <target default="1"> ?
442                 struct _xmlAttr *attr;
443                 for (attr = ptr->properties; attr; attr = attr->next)
444                     if (!strcmp((const char *) attr->name, "default") &&
445                         attr->children && attr->children->type == XML_TEXT_NODE)
446                     {
447                         xmlChar *t = attr->children->content;
448                         if (!t || *t == '1')
449                             return ptr;
450                     }
451             }
452             else
453             {
454                 // <target name="name"> ?
455                 struct _xmlAttr *attr;
456                 for (attr = ptr->properties; attr; attr = attr->next)
457                     if (!strcmp((const char *) attr->name, "name"))
458                     {
459                         if (attr->children
460                             && attr->children->type==XML_TEXT_NODE
461                             && attr->children->content 
462                             && (!strcmp((const char *) attr->children->content,
463                                         name)
464                                 || !strcmp((const char *) attr->children->content,
465                                            "*")))
466                         {
467                             return ptr;
468                         }
469                     }
470             }
471         }
472     }
473     return 0;
474 }
475 #endif
476
477 int Yaz_ProxyConfig::get_target_no(int no,
478                                    const char **name,
479                                    const char **url,
480                                    int *limit_bw,
481                                    int *limit_pdu,
482                                    int *limit_req,
483                                    int *target_idletime,
484                                    int *client_idletime,
485                                    int *max_clients,
486                                    int *keepalive_limit_bw,
487                                    int *keepalive_limit_pdu,
488                                    int *pre_init,
489                                    const char **cql2rpn,
490                                    const char **zeerex)
491 {
492 #if HAVE_XML2
493     xmlNodePtr ptr;
494     if (!m_proxyPtr)
495         return 0;
496     int i = 0;
497     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
498         if (ptr->type == XML_ELEMENT_NODE &&
499             !strcmp((const char *) ptr->name, "target"))
500         {
501             if (i == no)
502             {
503                 struct _xmlAttr *attr;
504                 for (attr = ptr->properties; attr; attr = attr->next)
505                     if (!strcmp((const char *) attr->name, "name"))
506                     {
507                         if (attr->children
508                             && attr->children->type==XML_TEXT_NODE
509                             && attr->children->content)
510                             *name = (const char *) attr->children->content;
511                     }
512                 return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
513                                    target_idletime, client_idletime,
514                                    keepalive_limit_bw, keepalive_limit_pdu,
515                                    pre_init, cql2rpn, zeerex);
516                 return 1;
517             }
518             i++;
519         }
520 #endif
521     return 0;
522 }
523
524 int Yaz_ProxyConfig::mycmp(const char *hay, const char *item, size_t len)
525 {
526     if (len == strlen(item) && memcmp(hay, item, len) == 0)
527         return 1;
528     return 0;
529 }
530
531 void Yaz_ProxyConfig::get_generic_info(int *log_mask,
532                                        int *max_clients)
533 {
534 #if HAVE_XML2
535     xmlNodePtr ptr;
536     if (!m_proxyPtr)
537         return;
538     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
539     {
540         if (ptr->type == XML_ELEMENT_NODE 
541             && !strcmp((const char *) ptr->name, "log"))
542         {
543             const char *v = get_text(ptr);
544             *log_mask = 0;
545             while (v && *v)
546             {
547                 const char *cp = v;
548                 while (*cp && *cp != ',' && !isspace(*cp))
549                     cp++;
550                 size_t len = cp - v;
551                 if (mycmp(v, "client-apdu", len))
552                     *log_mask |= PROXY_LOG_APDU_CLIENT;
553                 if (mycmp(v, "server-apdu", len))
554                     *log_mask |= PROXY_LOG_APDU_SERVER;
555                 if (mycmp(v, "client-requests", len))
556                     *log_mask |= PROXY_LOG_REQ_CLIENT;
557                 if (mycmp(v, "server-requests", len))
558                     *log_mask |= PROXY_LOG_REQ_SERVER;
559                 if (isdigit(*v))
560                     *log_mask |= atoi(v);
561                 if (*cp == ',')
562                     cp++;
563                 while (*cp && isspace(*cp))
564                     cp++;
565                 v = cp;
566             }
567         }
568         if (ptr->type == XML_ELEMENT_NODE &&
569             !strcmp((const char *) ptr->name, "max-clients"))
570         {
571             const char *t = get_text(ptr);
572             if (t)
573             {
574                 *max_clients = atoi(t);
575                 if (*max_clients  < 1)
576                     *max_clients = 1;
577             }
578         }
579     }
580 #endif
581 }
582
583 void Yaz_ProxyConfig::get_target_info(const char *name,
584                                       const char **url,
585                                       int *limit_bw,
586                                       int *limit_pdu,
587                                       int *limit_req,
588                                       int *target_idletime,
589                                       int *client_idletime,
590                                       int *max_clients,
591                                       int *keepalive_limit_bw,
592                                       int *keepalive_limit_pdu,
593                                       int *pre_init,
594                                       const char **cql2rpn,
595                                       const char **zeerex)
596 {
597 #if HAVE_XML2
598     xmlNodePtr ptr;
599     if (!m_proxyPtr)
600     {
601         url[0] = name;
602         url[1] = 0;
603         return;
604     }
605     url[0] = 0;
606     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
607     {
608         if (ptr->type == XML_ELEMENT_NODE &&
609             !strcmp((const char *) ptr->name, "max-clients"))
610         {
611             const char *t = get_text(ptr);
612             if (t)
613             {
614                 *max_clients = atoi(t);
615                 if (*max_clients  < 1)
616                     *max_clients = 1;
617             }
618         }
619     }
620     ptr = find_target_node(name);
621     if (ptr)
622     {
623         if (name)
624         {
625             url[0] = name;
626             url[1] = 0;
627         }
628         return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
629                            target_idletime, client_idletime,
630                            keepalive_limit_bw, keepalive_limit_pdu,
631                            pre_init, cql2rpn, zeerex);
632     }
633 #else
634     *url = name;
635     return;
636 #endif
637 }
638
639