Syntax validation. Log implementation stuff
[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.5 2003-10-08 08:15:01 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 void Yaz_ProxyConfig::operator=(const Yaz_ProxyConfig &conf)
30 {
31 #if HAVE_XML2
32     m_docPtr = conf.m_docPtr;
33     m_proxyPtr = conf.m_proxyPtr;
34 #endif
35     m_copy = 1;
36 }
37
38 int Yaz_ProxyConfig::read_xml(const char *fname)
39 {
40 #if HAVE_XML2
41     xmlDocPtr ndoc = xmlParseFile(fname);
42
43     if (!ndoc)
44     {
45         yaz_log(LOG_WARN, "Config file %s not found or parse error", fname);
46         return -1;  // no good
47     }
48     xmlNodePtr proxyPtr = xmlDocGetRootElement(ndoc);
49     if (!proxyPtr || proxyPtr->type != XML_ELEMENT_NODE ||
50         strcmp((const char *) proxyPtr->name, "proxy"))
51     {
52         yaz_log(LOG_WARN, "No proxy element in %s", fname);
53         xmlFreeDoc(ndoc);
54         return -1;
55     }
56     m_proxyPtr = proxyPtr;
57
58     // OK: release previous and make it the current one.
59     if (m_docPtr)
60         xmlFreeDoc(m_docPtr);
61     m_docPtr = ndoc;
62     return 0;
63 #else
64     return -2;
65 #endif
66 }
67
68 #if HAVE_XML2
69 const char *Yaz_ProxyConfig::get_text(xmlNodePtr ptr)
70 {
71     for(ptr = ptr->children; ptr; ptr = ptr->next)
72         if (ptr->type == XML_TEXT_NODE)
73         {
74             xmlChar *t = ptr->content;
75             if (t)
76             {
77                 while (*t == ' ')
78                     t++;
79                 return (const char *) t;
80             }
81         }
82     return 0;
83 }
84 #endif
85
86 #if HAVE_XML2
87 void Yaz_ProxyConfig::return_limit(xmlNodePtr ptr,
88                                    int *limit_bw,
89                                    int *limit_pdu,
90                                    int *limit_req)
91 {
92     for (ptr = ptr->children; ptr; ptr = ptr->next)
93     {
94         if (ptr->type == XML_ELEMENT_NODE 
95             && !strcmp((const char *) ptr->name, "bandwidth"))
96         {
97             const char *t = get_text(ptr);
98             if (t)
99                 *limit_bw = atoi(t);
100         }
101         if (ptr->type == XML_ELEMENT_NODE 
102             && !strcmp((const char *) ptr->name, "retrieve"))
103         {
104             const char *t = get_text(ptr);
105             if (t)
106                 *limit_req = atoi(t);
107         }
108         if (ptr->type == XML_ELEMENT_NODE 
109             && !strcmp((const char *) ptr->name, "pdu"))
110         {
111             const char *t = get_text(ptr);
112             if (t)
113                 *limit_pdu = atoi(t);
114         }
115     }
116 }
117 #endif
118
119 #if HAVE_XML2
120 void Yaz_ProxyConfig::return_target_info(xmlNodePtr ptr,
121                                          const char **url,
122                                          int *keepalive,
123                                          int *limit_bw,
124                                          int *limit_pdu,
125                                          int *limit_req,
126                                          int *target_idletime,
127                                          int *client_idletime)
128 {
129     ptr = ptr->children;
130     for (; ptr; ptr = ptr->next)
131     {
132         if (ptr->type == XML_ELEMENT_NODE 
133             && !strcmp((const char *) ptr->name, "url"))
134         {
135             const char *t = get_text(ptr);
136             if (t)
137                 *url = t;
138         }
139         if (ptr->type == XML_ELEMENT_NODE 
140             && !strcmp((const char *) ptr->name, "keepalive"))
141         {
142             const char *t = get_text(ptr);
143             if (!t || *t == '1')
144                 *keepalive = 1;
145             else
146                 *keepalive = 0;
147         }
148         if (ptr->type == XML_ELEMENT_NODE 
149             && !strcmp((const char *) ptr->name, "limit"))
150             return_limit(ptr, limit_bw, limit_pdu, limit_req);
151         if (ptr->type == XML_ELEMENT_NODE 
152             && !strcmp((const char *) ptr->name, "target-timeout"))
153         {
154             const char *t = get_text(ptr);
155             if (t)
156             {
157                 *target_idletime = atoi(t);
158                 if (*target_idletime < 0)
159                     *target_idletime = 0;
160             }
161         }
162         if (ptr->type == XML_ELEMENT_NODE 
163             && !strcmp((const char *) ptr->name, "client-timeout"))
164         {
165             const char *t = get_text(ptr);
166             if (t)
167             {
168                 *client_idletime = atoi(t);
169                 if (*client_idletime < 0)
170                     *client_idletime = 0;
171             }
172         }
173     }
174 }
175 #endif
176
177 int Yaz_ProxyConfig::atoi_l(const char **cp)
178 {
179     int v = 0;
180     while (**cp && isdigit(**cp))
181     {
182         v = v*10 + (**cp - '0');
183         (*cp)++;
184     }
185     return v;
186 }
187
188 int Yaz_ProxyConfig::match_list(int v, const char *m)
189 {
190   while(m && *m)
191   {
192       while(*m && isspace(*m))
193           m++;
194       if (*m == '*')
195           return 1;
196       int l = atoi_l(&m);
197       int h = l;
198       if (*m == '-')
199       {
200           ++m;
201           h = atoi_l(&m);
202       }
203       if (v >= l && v <= h)
204           return 1;
205       if (*m == ',')
206           m++;
207   }
208   return 0;
209 }
210
211 #if HAVE_XML2
212 int Yaz_ProxyConfig::check_type_1_attributes(ODR odr, xmlNodePtr ptr,
213                                              Z_AttributeList *attrs,
214                                              char **addinfo)
215 {
216     for(ptr = ptr->children; ptr; ptr = ptr->next)
217     {
218         if (ptr->type == XML_ELEMENT_NODE &&
219             !strcmp((const char *) ptr->name, "query"))
220         {
221             const char *match_type = 0;
222             const char *match_value = 0;
223             const char *match_error = 0;
224             struct _xmlAttr *attr;
225             for (attr = ptr->properties; attr; attr = attr->next)
226             {
227                 if (!strcmp((const char *) attr->name, "type") &&
228                     attr->children && attr->children->type == XML_TEXT_NODE)
229                     match_type = (const char *) attr->children->content;
230                 if (!strcmp((const char *) attr->name, "value") &&
231                     attr->children && attr->children->type == XML_TEXT_NODE)
232                     match_value = (const char *) attr->children->content;
233                 if (!strcmp((const char *) attr->name, "error") &&
234                     attr->children && attr->children->type == XML_TEXT_NODE)
235                     match_error = (const char *) attr->children->content;
236             }
237             int i;
238
239             if (match_type && match_value)
240             {
241                 for (i = 0; i<attrs->num_attributes; i++)
242                 {
243                     Z_AttributeElement *el = attrs->attributes[i];
244                     char value_str[20];
245                     
246                     value_str[0] = '\0';
247                     if (!el->attributeType)
248                         continue;
249                     int type = *el->attributeType;
250
251                     if (!match_list(type, match_type))
252                         continue;
253                     if (el->which == Z_AttributeValue_numeric && 
254                         el->value.numeric)
255                     {
256                         if (!match_list(*el->value.numeric, match_value))
257                             continue;
258                         sprintf (value_str, "%d", *el->value.numeric);
259                     }
260                     else
261                         continue;
262                     if (match_error)
263                     {
264                         if (*value_str)
265                             *addinfo = odr_strdup(odr, value_str);
266                         return atoi(match_error);
267                     }
268                     return 0;
269                 }
270             }
271         }
272     }
273     return 0;
274 }
275 #endif
276
277 #if HAVE_XML2
278 int Yaz_ProxyConfig::check_type_1_structure(ODR odr, xmlNodePtr ptr,
279                                             Z_RPNStructure *q,
280                                             char **addinfo)
281 {
282     int c;
283     if (q->which == Z_RPNStructure_complex)
284     {
285         int e = check_type_1_structure(odr, ptr, q->u.complex->s1, addinfo);
286         if (e)
287             return e;
288         e = check_type_1_structure(odr, ptr, q->u.complex->s2, addinfo);
289         return e;
290     }
291     else if (q->which == Z_RPNStructure_simple)
292     {
293         if (q->u.simple->which == Z_Operand_APT)
294         {
295             return check_type_1_attributes(
296                 odr, ptr, q->u.simple->u.attributesPlusTerm->attributes,
297                 addinfo);
298         }
299     }
300     return 0;
301 }
302 #endif
303
304 #if HAVE_XML2
305 int Yaz_ProxyConfig::check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
306                                   char **addinfo)
307 {
308     // possibly check for Bib-1
309     return check_type_1_structure(odr, ptr, query->RPNStructure, addinfo);
310 }
311 #endif
312
313 int Yaz_ProxyConfig::check_query(ODR odr, const char *name, Z_Query *query,
314                                  char **addinfo)
315 {
316 #if HAVE_XML2
317     xmlNodePtr ptr;
318     
319     ptr = find_target_node(name);
320     if (ptr)
321     {
322         if (query->which == Z_Query_type_1 || query->which == Z_Query_type_101)
323             return check_type_1(odr, ptr, query->u.type_1, addinfo);
324     }
325 #endif
326     return 0;
327 }
328
329 int Yaz_ProxyConfig::check_syntax(ODR odr, const char *name,
330                                   Odr_oid *syntax, char **addinfo)
331 {
332 #if HAVE_XML2
333     xmlNodePtr ptr;
334     
335     ptr = find_target_node(name);
336     if (!ptr)
337         return 0;
338     for(ptr = ptr->children; ptr; ptr = ptr->next)
339     {
340         if (ptr->type == XML_ELEMENT_NODE &&
341             !strcmp((const char *) ptr->name, "syntax"))
342         {
343             int match = 0;  // if we match record syntax
344             const char *match_type = 0;
345             const char *match_error = 0;
346             struct _xmlAttr *attr;
347             for (attr = ptr->properties; attr; attr = attr->next)
348             {
349                 if (!strcmp((const char *) attr->name, "type") &&
350                     attr->children && attr->children->type == XML_TEXT_NODE)
351                     match_type = (const char *) attr->children->content;
352                 if (!strcmp((const char *) attr->name, "error") &&
353                     attr->children && attr->children->type == XML_TEXT_NODE)
354                     match_error = (const char *) attr->children->content;
355             }
356             if (match_type)
357             {
358                 if (!strcmp(match_type, "*"))
359                     match = 1;
360                 else if (!strcmp(match_type, "none"))
361                 {
362                     if (syntax == 0)
363                         match = 1;
364                 }
365                 else if (syntax)
366                 {
367                     int match_oid[OID_SIZE];
368                     oid_name_to_oid(CLASS_RECSYN, match_type, match_oid);
369                     if (oid_oidcmp(match_oid, syntax) == 0)
370                         match = 1;
371                 }
372             }
373             if (match)
374             {
375                 if (match_error)
376                 {
377                     if (syntax)
378                     {
379                         char dotoid_str[100];
380                         oid_to_dotstring(syntax, dotoid_str);
381                         *addinfo = odr_strdup(odr, dotoid_str);
382                     }
383                     return atoi(match_error);
384                 }
385                 return 0;
386             }
387         }
388     }
389 #endif
390     return 0;
391 }
392
393 #if HAVE_XML2
394 xmlNodePtr Yaz_ProxyConfig::find_target_node(const char *name)
395 {
396     xmlNodePtr ptr;
397     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
398     {
399         if (ptr->type == XML_ELEMENT_NODE &&
400             !strcmp((const char *) ptr->name, "target"))
401         {
402             // default one ? 
403             if (!name)
404             {
405                 // <target default="1"> ?
406                 struct _xmlAttr *attr;
407                 for (attr = ptr->properties; attr; attr = attr->next)
408                     if (!strcmp((const char *) attr->name, "default") &&
409                         attr->children && attr->children->type == XML_TEXT_NODE)
410                     {
411                         xmlChar *t = attr->children->content;
412                         if (!t || *t == '1')
413                             return ptr;
414                     }
415             }
416             else
417             {
418                 // <target name="name"> ?
419                 struct _xmlAttr *attr;
420                 for (attr = ptr->properties; attr; attr = attr->next)
421                     if (!strcmp((const char *) attr->name, "name"))
422                     {
423                         if (attr->children
424                             && attr->children->type==XML_TEXT_NODE
425                             && attr->children->content 
426                             && (!strcmp((const char *) attr->children->content,
427                                         name)
428                                 || !strcmp((const char *) attr->children->content,
429                                            "*")))
430                         {
431                             return ptr;
432                         }
433                     }
434             }
435         }
436     }
437     return 0;
438 }
439 #endif
440
441 void Yaz_ProxyConfig::get_target_info(const char *name,
442                                       const char **url,
443                                       int *keepalive,
444                                       int *limit_bw,
445                                       int *limit_pdu,
446                                       int *limit_req,
447                                       int *target_idletime,
448                                       int *client_idletime,
449                                       int *max_clients)
450 {
451 #if HAVE_XML2
452     xmlNodePtr ptr;
453     if (!m_proxyPtr)
454     {
455         *url = name;
456         return;
457     }
458     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
459     {
460         if (ptr->type == XML_ELEMENT_NODE &&
461             !strcmp((const char *) ptr->name, "max-clients"))
462         {
463             const char *t = get_text(ptr);
464             if (t)
465             {
466                 *max_clients = atoi(t);
467                 if (*max_clients  < 1)
468                     *max_clients = 1;
469             }
470         }
471     }
472     ptr = find_target_node(name);
473     if (ptr)
474     {
475         if (name)
476             *url = name;
477         return_target_info(ptr, url, keepalive, limit_bw, limit_pdu, limit_req,
478                            target_idletime, client_idletime);
479     }
480 #else
481     *url = name;
482     return;
483 #endif
484 }
485
486