Start work on log options
[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.10 2003-10-16 13:40:41 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                                          int *log_mask)
122 {
123     *pre_init = 0;
124     int no_url = 0;
125     ptr = ptr->children;
126     for (; ptr; ptr = ptr->next)
127     {
128         if (ptr->type == XML_ELEMENT_NODE 
129             && !strcmp((const char *) ptr->name, "log"))
130         {
131             const char *v = get_text(ptr);
132             *log_mask = 0;
133             while (v && *v)
134             {
135                 const char *cp = v;
136                 while (*cp && *cp != ',' && !isspace(*cp))
137                     cp++;
138                 size_t len = cp - v;
139                 if (len == 4 && !memcmp(v, "apdu", 4))
140                     *log_mask |= PROXY_LOG_APDU;
141                 if (len == 3 && !memcmp(v, "req", 3))
142                     *log_mask |= PROXY_LOG_REQ;
143                 if (isdigit(*v))
144                     *log_mask |= atoi(v);
145                 if (*cp == ',')
146                     cp++;
147                 while (*cp && isspace(*cp))
148                     cp++;
149                 v = cp;
150             }
151         }
152         if (ptr->type == XML_ELEMENT_NODE 
153             && !strcmp((const char *) ptr->name, "preinit"))
154         {
155             const char *v = get_text(ptr);
156             *pre_init = v ? atoi(v) : 1;
157         }
158         if (ptr->type == XML_ELEMENT_NODE 
159             && !strcmp((const char *) ptr->name, "url"))
160         {
161             const char *t = get_text(ptr);
162             if (t && no_url < MAX_ZURL_PLEX)
163             {
164                 url[no_url++] = t;
165                 url[no_url] = 0;
166             }
167         }
168         if (ptr->type == XML_ELEMENT_NODE 
169             && !strcmp((const char *) ptr->name, "keepalive"))
170         {
171             int dummy;
172             *keepalive_limit_bw = 500000;
173             *keepalive_limit_pdu = 1000;
174             return_limit(ptr, keepalive_limit_bw, keepalive_limit_pdu,
175                          &dummy);
176         }
177         if (ptr->type == XML_ELEMENT_NODE 
178             && !strcmp((const char *) ptr->name, "limit"))
179             return_limit(ptr, limit_bw, limit_pdu, limit_req);
180         if (ptr->type == XML_ELEMENT_NODE 
181             && !strcmp((const char *) ptr->name, "target-timeout"))
182         {
183             const char *t = get_text(ptr);
184             if (t)
185             {
186                 *target_idletime = atoi(t);
187                 if (*target_idletime < 0)
188                     *target_idletime = 0;
189             }
190         }
191         if (ptr->type == XML_ELEMENT_NODE 
192             && !strcmp((const char *) ptr->name, "client-timeout"))
193         {
194             const char *t = get_text(ptr);
195             if (t)
196             {
197                 *client_idletime = atoi(t);
198                 if (*client_idletime < 0)
199                     *client_idletime = 0;
200             }
201         }
202     }
203 }
204 #endif
205
206 int Yaz_ProxyConfig::atoi_l(const char **cp)
207 {
208     int v = 0;
209     while (**cp && isdigit(**cp))
210     {
211         v = v*10 + (**cp - '0');
212         (*cp)++;
213     }
214     return v;
215 }
216
217 int Yaz_ProxyConfig::match_list(int v, const char *m)
218 {
219   while(m && *m)
220   {
221       while(*m && isspace(*m))
222           m++;
223       if (*m == '*')
224           return 1;
225       int l = atoi_l(&m);
226       int h = l;
227       if (*m == '-')
228       {
229           ++m;
230           h = atoi_l(&m);
231       }
232       if (v >= l && v <= h)
233           return 1;
234       if (*m == ',')
235           m++;
236   }
237   return 0;
238 }
239
240 #if HAVE_XML2
241 int Yaz_ProxyConfig::check_type_1_attributes(ODR odr, xmlNodePtr ptr,
242                                              Z_AttributeList *attrs,
243                                              char **addinfo)
244 {
245     for(ptr = ptr->children; ptr; ptr = ptr->next)
246     {
247         if (ptr->type == XML_ELEMENT_NODE &&
248             !strcmp((const char *) ptr->name, "attribute"))
249         {
250             const char *match_type = 0;
251             const char *match_value = 0;
252             const char *match_error = 0;
253             struct _xmlAttr *attr;
254             for (attr = ptr->properties; attr; attr = attr->next)
255             {
256                 if (!strcmp((const char *) attr->name, "type") &&
257                     attr->children && attr->children->type == XML_TEXT_NODE)
258                     match_type = (const char *) attr->children->content;
259                 if (!strcmp((const char *) attr->name, "value") &&
260                     attr->children && attr->children->type == XML_TEXT_NODE)
261                     match_value = (const char *) attr->children->content;
262                 if (!strcmp((const char *) attr->name, "error") &&
263                     attr->children && attr->children->type == XML_TEXT_NODE)
264                     match_error = (const char *) attr->children->content;
265             }
266             int i;
267
268             if (match_type && match_value)
269             {
270                 for (i = 0; i<attrs->num_attributes; i++)
271                 {
272                     Z_AttributeElement *el = attrs->attributes[i];
273                     char value_str[20];
274                     
275                     value_str[0] = '\0';
276                     if (!el->attributeType)
277                         continue;
278                     int type = *el->attributeType;
279
280                     if (!match_list(type, match_type))
281                         continue;
282                     if (el->which == Z_AttributeValue_numeric && 
283                         el->value.numeric)
284                     {
285                         if (!match_list(*el->value.numeric, match_value))
286                             continue;
287                         sprintf (value_str, "%d", *el->value.numeric);
288                     }
289                     else
290                         continue;
291                     if (match_error)
292                     {
293                         if (*value_str)
294                             *addinfo = odr_strdup(odr, value_str);
295                         return atoi(match_error);
296                     }
297                     return 0;
298                 }
299             }
300         }
301     }
302     return 0;
303 }
304 #endif
305
306 #if HAVE_XML2
307 int Yaz_ProxyConfig::check_type_1_structure(ODR odr, xmlNodePtr ptr,
308                                             Z_RPNStructure *q,
309                                             char **addinfo)
310 {
311     int c;
312     if (q->which == Z_RPNStructure_complex)
313     {
314         int e = check_type_1_structure(odr, ptr, q->u.complex->s1, addinfo);
315         if (e)
316             return e;
317         e = check_type_1_structure(odr, ptr, q->u.complex->s2, addinfo);
318         return e;
319     }
320     else if (q->which == Z_RPNStructure_simple)
321     {
322         if (q->u.simple->which == Z_Operand_APT)
323         {
324             return check_type_1_attributes(
325                 odr, ptr, q->u.simple->u.attributesPlusTerm->attributes,
326                 addinfo);
327         }
328     }
329     return 0;
330 }
331 #endif
332
333 #if HAVE_XML2
334 int Yaz_ProxyConfig::check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
335                                   char **addinfo)
336 {
337     // possibly check for Bib-1
338     return check_type_1_structure(odr, ptr, query->RPNStructure, addinfo);
339 }
340 #endif
341
342 int Yaz_ProxyConfig::check_query(ODR odr, const char *name, Z_Query *query,
343                                  char **addinfo)
344 {
345 #if HAVE_XML2
346     xmlNodePtr ptr;
347     
348     ptr = find_target_node(name);
349     if (ptr)
350     {
351         if (query->which == Z_Query_type_1 || query->which == Z_Query_type_101)
352             return check_type_1(odr, ptr, query->u.type_1, addinfo);
353     }
354 #endif
355     return 0;
356 }
357
358 int Yaz_ProxyConfig::check_syntax(ODR odr, const char *name,
359                                   Odr_oid *syntax, char **addinfo)
360 {
361 #if HAVE_XML2
362     xmlNodePtr ptr;
363     
364     ptr = find_target_node(name);
365     if (!ptr)
366         return 0;
367     for(ptr = ptr->children; ptr; ptr = ptr->next)
368     {
369         if (ptr->type == XML_ELEMENT_NODE &&
370             !strcmp((const char *) ptr->name, "syntax"))
371         {
372             int match = 0;  // if we match record syntax
373             const char *match_type = 0;
374             const char *match_error = 0;
375             const char *match_marcxml = 0;
376             struct _xmlAttr *attr;
377             for (attr = ptr->properties; attr; attr = attr->next)
378             {
379                 if (!strcmp((const char *) attr->name, "type") &&
380                     attr->children && attr->children->type == XML_TEXT_NODE)
381                     match_type = (const char *) attr->children->content;
382                 if (!strcmp((const char *) attr->name, "error") &&
383                     attr->children && attr->children->type == XML_TEXT_NODE)
384                     match_error = (const char *) attr->children->content;
385                 if (!strcmp((const char *) attr->name, "marcxml") &&
386                     attr->children && attr->children->type == XML_TEXT_NODE)
387                     match_marcxml = (const char *) attr->children->content;
388             }
389             if (match_type)
390             {
391                 if (!strcmp(match_type, "*"))
392                     match = 1;
393                 else if (!strcmp(match_type, "none"))
394                 {
395                     if (syntax == 0)
396                         match = 1;
397                 }
398                 else if (syntax)
399                 {
400                     int match_oid[OID_SIZE];
401                     oid_name_to_oid(CLASS_RECSYN, match_type, match_oid);
402                     if (oid_oidcmp(match_oid, syntax) == 0)
403                         match = 1;
404                 }
405             }
406             if (match)
407             {
408                 if (match_marcxml)
409                 {
410                     return -1;
411                 }
412                 if (match_error)
413                 {
414                     if (syntax)
415                     {
416                         char dotoid_str[100];
417                         oid_to_dotstring(syntax, dotoid_str);
418                         *addinfo = odr_strdup(odr, dotoid_str);
419                     }
420                     return atoi(match_error);
421                 }
422                 return 0;
423             }
424         }
425     }
426 #endif
427     return 0;
428 }
429
430 #if HAVE_XML2
431 xmlNodePtr Yaz_ProxyConfig::find_target_node(const char *name)
432 {
433     xmlNodePtr ptr;
434     if (!m_proxyPtr)
435         return 0;
436     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
437     {
438         if (ptr->type == XML_ELEMENT_NODE &&
439             !strcmp((const char *) ptr->name, "target"))
440         {
441             // default one ? 
442             if (!name)
443             {
444                 // <target default="1"> ?
445                 struct _xmlAttr *attr;
446                 for (attr = ptr->properties; attr; attr = attr->next)
447                     if (!strcmp((const char *) attr->name, "default") &&
448                         attr->children && attr->children->type == XML_TEXT_NODE)
449                     {
450                         xmlChar *t = attr->children->content;
451                         if (!t || *t == '1')
452                             return ptr;
453                     }
454             }
455             else
456             {
457                 // <target name="name"> ?
458                 struct _xmlAttr *attr;
459                 for (attr = ptr->properties; attr; attr = attr->next)
460                     if (!strcmp((const char *) attr->name, "name"))
461                     {
462                         if (attr->children
463                             && attr->children->type==XML_TEXT_NODE
464                             && attr->children->content 
465                             && (!strcmp((const char *) attr->children->content,
466                                         name)
467                                 || !strcmp((const char *) attr->children->content,
468                                            "*")))
469                         {
470                             return ptr;
471                         }
472                     }
473             }
474         }
475     }
476     return 0;
477 }
478 #endif
479
480 int Yaz_ProxyConfig::get_target_no(int no,
481                                    const char **name,
482                                    const char **url,
483                                    int *limit_bw,
484                                    int *limit_pdu,
485                                    int *limit_req,
486                                    int *target_idletime,
487                                    int *client_idletime,
488                                    int *max_clients,
489                                    int *keepalive_limit_bw,
490                                    int *keepalive_limit_pdu,
491                                    int *pre_init,
492                                    int *log_mask)
493 {
494 #if HAVE_XML2
495     xmlNodePtr ptr;
496     if (!m_proxyPtr)
497         return 0;
498     int i = 0;
499     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
500         if (ptr->type == XML_ELEMENT_NODE &&
501             !strcmp((const char *) ptr->name, "target"))
502         {
503             if (i == no)
504             {
505                 struct _xmlAttr *attr;
506                 for (attr = ptr->properties; attr; attr = attr->next)
507                     if (!strcmp((const char *) attr->name, "name"))
508                     {
509                         if (attr->children
510                             && attr->children->type==XML_TEXT_NODE
511                             && attr->children->content)
512                             *name = (const char *) attr->children->content;
513                     }
514                 return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
515                                    target_idletime, client_idletime,
516                                    keepalive_limit_bw, keepalive_limit_pdu,
517                                    pre_init, log_mask);
518                 return 1;
519             }
520             i++;
521         }
522 #endif
523     return 0;
524 }
525
526 void Yaz_ProxyConfig::get_target_info(const char *name,
527                                       const char **url,
528                                       int *limit_bw,
529                                       int *limit_pdu,
530                                       int *limit_req,
531                                       int *target_idletime,
532                                       int *client_idletime,
533                                       int *max_clients,
534                                       int *keepalive_limit_bw,
535                                       int *keepalive_limit_pdu,
536                                       int *pre_init,
537                                       int *log_mask)
538 {
539 #if HAVE_XML2
540     xmlNodePtr ptr;
541     if (!m_proxyPtr)
542     {
543         url[0] = name;
544         url[1] = 0;
545         return;
546     }
547     url[0] = 0;
548     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
549     {
550         if (ptr->type == XML_ELEMENT_NODE &&
551             !strcmp((const char *) ptr->name, "max-clients"))
552         {
553             const char *t = get_text(ptr);
554             if (t)
555             {
556                 *max_clients = atoi(t);
557                 if (*max_clients  < 1)
558                     *max_clients = 1;
559             }
560         }
561     }
562     ptr = find_target_node(name);
563     if (ptr)
564     {
565         if (name)
566         {
567             url[0] = name;
568             url[1] = 0;
569         }
570         return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
571                            target_idletime, client_idletime,
572                            keepalive_limit_bw, keepalive_limit_pdu,
573                            pre_init, log_mask);
574     }
575 #else
576     *url = name;
577     return;
578 #endif
579 }
580
581