Allow ranges for query attributes
[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.4 2003-10-06 08:08:49 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 #if HAVE_XML2
330 xmlNodePtr Yaz_ProxyConfig::find_target_node(const char *name)
331 {
332     xmlNodePtr ptr;
333     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
334     {
335         if (ptr->type == XML_ELEMENT_NODE &&
336             !strcmp((const char *) ptr->name, "target"))
337         {
338             // default one ? 
339             if (!name)
340             {
341                 // <target default="1"> ?
342                 struct _xmlAttr *attr;
343                 for (attr = ptr->properties; attr; attr = attr->next)
344                     if (!strcmp((const char *) attr->name, "default") &&
345                         attr->children && attr->children->type == XML_TEXT_NODE)
346                     {
347                         xmlChar *t = attr->children->content;
348                         if (!t || *t == '1')
349                             return ptr;
350                     }
351             }
352             else
353             {
354                 // <target name="name"> ?
355                 struct _xmlAttr *attr;
356                 for (attr = ptr->properties; attr; attr = attr->next)
357                     if (!strcmp((const char *) attr->name, "name"))
358                     {
359                         if (attr->children
360                             && attr->children->type==XML_TEXT_NODE
361                             && attr->children->content 
362                             && (!strcmp((const char *) attr->children->content,
363                                         name)
364                                 || !strcmp((const char *) attr->children->content,
365                                            "*")))
366                         {
367                             return ptr;
368                         }
369                     }
370             }
371         }
372     }
373     return 0;
374 }
375 #endif
376
377 void Yaz_ProxyConfig::get_target_info(const char *name,
378                                       const char **url,
379                                       int *keepalive,
380                                       int *limit_bw,
381                                       int *limit_pdu,
382                                       int *limit_req,
383                                       int *target_idletime,
384                                       int *client_idletime,
385                                       int *max_clients)
386 {
387 #if HAVE_XML2
388     xmlNodePtr ptr;
389     if (!m_proxyPtr)
390     {
391         *url = name;
392         return;
393     }
394     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
395     {
396         if (ptr->type == XML_ELEMENT_NODE &&
397             !strcmp((const char *) ptr->name, "max-clients"))
398         {
399             const char *t = get_text(ptr);
400             if (t)
401             {
402                 *max_clients = atoi(t);
403                 if (*max_clients  < 1)
404                     *max_clients = 1;
405             }
406         }
407     }
408     ptr = find_target_node(name);
409     if (ptr)
410     {
411         if (name)
412             *url = name;
413         return_target_info(ptr, url, keepalive, limit_bw, limit_pdu, limit_req,
414                            target_idletime, client_idletime);
415     }
416 #else
417     *url = name;
418     return;
419 #endif
420 }
421
422