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