User-defined error handling for queries in proxy
[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.2 2003-10-03 13:01:42 adam Exp $
6  */
7
8 #include <yaz/log.h>
9 #include <yaz++/proxy.h>
10
11 Yaz_ProxyConfig::Yaz_ProxyConfig()
12 {
13     m_copy = 0;
14 #if HAVE_XML2
15     m_docPtr = 0;
16     m_proxyPtr = 0;
17 #endif
18 }
19
20 Yaz_ProxyConfig::~Yaz_ProxyConfig()
21 {
22 #if HAVE_XML2
23     if (!m_copy && m_docPtr)
24         xmlFreeDoc(m_docPtr);
25 #endif
26 }
27
28 void Yaz_ProxyConfig::operator=(const Yaz_ProxyConfig &conf)
29 {
30 #if HAVE_XML2
31     m_docPtr = conf.m_docPtr;
32     m_proxyPtr = conf.m_proxyPtr;
33 #endif
34     m_copy = 1;
35 }
36
37 int Yaz_ProxyConfig::read_xml(const char *fname)
38 {
39 #if HAVE_XML2
40     xmlDocPtr ndoc = xmlParseFile(fname);
41
42     if (!ndoc)
43     {
44         yaz_log(LOG_WARN, "Config file %s not found or parse error", fname);
45         return -1;  // no good
46     }
47     xmlNodePtr proxyPtr = xmlDocGetRootElement(ndoc);
48     if (!proxyPtr || proxyPtr->type != XML_ELEMENT_NODE ||
49         strcmp((const char *) proxyPtr->name, "proxy"))
50     {
51         yaz_log(LOG_WARN, "No proxy element in %s", fname);
52         xmlFreeDoc(ndoc);
53         return -1;
54     }
55     m_proxyPtr = proxyPtr;
56
57     // OK: release previous and make it the current one.
58     if (m_docPtr)
59         xmlFreeDoc(m_docPtr);
60     m_docPtr = ndoc;
61     return 0;
62 #else
63     return -2;
64 #endif
65 }
66
67 #if HAVE_XML2
68 const char *Yaz_ProxyConfig::get_text(xmlNodePtr ptr)
69 {
70     for(ptr = ptr->children; ptr; ptr = ptr->next)
71         if (ptr->type == XML_TEXT_NODE)
72         {
73             xmlChar *t = ptr->content;
74             if (t)
75             {
76                 while (*t == ' ')
77                     t++;
78                 return (const char *) t;
79             }
80         }
81     return 0;
82 }
83 #endif
84
85 #if HAVE_XML2
86 void Yaz_ProxyConfig::return_limit(xmlNodePtr ptr,
87                                    int *limit_bw,
88                                    int *limit_pdu,
89                                    int *limit_req)
90 {
91     for (ptr = ptr->children; ptr; ptr = ptr->next)
92     {
93         if (ptr->type == XML_ELEMENT_NODE 
94             && !strcmp((const char *) ptr->name, "bandwidth"))
95         {
96             const char *t = get_text(ptr);
97             if (t)
98                 *limit_bw = atoi(t);
99         }
100         if (ptr->type == XML_ELEMENT_NODE 
101             && !strcmp((const char *) ptr->name, "retrieve"))
102         {
103             const char *t = get_text(ptr);
104             if (t)
105                 *limit_req = atoi(t);
106         }
107         if (ptr->type == XML_ELEMENT_NODE 
108             && !strcmp((const char *) ptr->name, "pdu"))
109         {
110             const char *t = get_text(ptr);
111             if (t)
112                 *limit_pdu = atoi(t);
113         }
114     }
115 }
116 #endif
117
118 #if HAVE_XML2
119 void Yaz_ProxyConfig::return_target_info(xmlNodePtr ptr,
120                                          const char **url,
121                                          int *keepalive,
122                                          int *limit_bw,
123                                          int *limit_pdu,
124                                          int *limit_req,
125                                          int *target_idletime,
126                                          int *client_idletime)
127 {
128     ptr = ptr->children;
129     for (; ptr; ptr = ptr->next)
130     {
131         if (ptr->type == XML_ELEMENT_NODE 
132             && !strcmp((const char *) ptr->name, "url"))
133         {
134             const char *t = get_text(ptr);
135             if (t)
136                 *url = t;
137         }
138         if (ptr->type == XML_ELEMENT_NODE 
139             && !strcmp((const char *) ptr->name, "keepalive"))
140         {
141             const char *t = get_text(ptr);
142             if (!t || *t == '1')
143                 *keepalive = 1;
144             else
145                 *keepalive = 0;
146         }
147         if (ptr->type == XML_ELEMENT_NODE 
148             && !strcmp((const char *) ptr->name, "limit"))
149             return_limit(ptr, limit_bw, limit_pdu, limit_req);
150         if (ptr->type == XML_ELEMENT_NODE 
151             && !strcmp((const char *) ptr->name, "target-timeout"))
152         {
153             const char *t = get_text(ptr);
154             if (t)
155             {
156                 *target_idletime = atoi(t);
157                 if (*target_idletime < 0)
158                     *target_idletime = 0;
159             }
160         }
161         if (ptr->type == XML_ELEMENT_NODE 
162             && !strcmp((const char *) ptr->name, "client-timeout"))
163         {
164             const char *t = get_text(ptr);
165             if (t)
166             {
167                 *client_idletime = atoi(t);
168                 if (*client_idletime < 0)
169                     *client_idletime = 0;
170             }
171         }
172     }
173 }
174 #endif
175
176 int Yaz_ProxyConfig::check_type_1_attributes(ODR odr, xmlNodePtr ptr,
177                                              Z_AttributeList *attrs,
178                                              char **addinfo)
179 {
180     for(ptr = ptr->children; ptr; ptr = ptr->next)
181     {
182         if (ptr->type == XML_ELEMENT_NODE &&
183             !strcmp((const char *) ptr->name, "query"))
184         {
185             const char *match_type = 0;
186             const char *match_value = 0;
187             const char *match_error = 0;
188             struct _xmlAttr *attr;
189             for (attr = ptr->properties; attr; attr = attr->next)
190             {
191                 if (!strcmp((const char *) attr->name, "type") &&
192                     attr->children && attr->children->type == XML_TEXT_NODE)
193                     match_type = (const char *) attr->children->content;
194                 if (!strcmp((const char *) attr->name, "value") &&
195                     attr->children && attr->children->type == XML_TEXT_NODE)
196                     match_value = (const char *) attr->children->content;
197                 if (!strcmp((const char *) attr->name, "error") &&
198                     attr->children && attr->children->type == XML_TEXT_NODE)
199                     match_error = (const char *) attr->children->content;
200             }
201             int i;
202
203             if (match_type && match_value)
204             {
205                 for (i = 0; i<attrs->num_attributes; i++)
206                 {
207                     Z_AttributeElement *el = attrs->attributes[i];
208                     char value_str[20];
209                     
210                     value_str[0] = '\0';
211                     if (!el->attributeType)
212                         continue;
213                     int type = *el->attributeType;
214
215                     if (strcmp(match_type, "*")) {
216                         if (type != atoi(match_type))
217                             continue;  // no match on type
218                     }
219                     if (el->which == Z_AttributeValue_numeric && 
220                         el->value.numeric)
221                     {
222                         int value = *el->value.numeric;
223                         if (strcmp(match_value, "*")) {
224                             if (value != atoi(match_value))
225                                 continue;  // no match on value
226                         }
227                         sprintf(value_str, "%d", value);
228                     }
229                     else
230                         continue;
231                     if (match_error)
232                     {
233                         if (*value_str)
234                             *addinfo = odr_strdup(odr, value_str);
235                         return atoi(match_error);
236                     }
237                     return 0;
238                 }
239             }
240         }
241     }
242     return 0;
243 }
244
245 int Yaz_ProxyConfig::check_type_1_structure(ODR odr, xmlNodePtr ptr,
246                                             Z_RPNStructure *q,
247                                             char **addinfo)
248 {
249     int c;
250     if (q->which == Z_RPNStructure_complex)
251     {
252         int e = check_type_1_structure(odr, ptr, q->u.complex->s1, addinfo);
253         if (e)
254             return e;
255         e = check_type_1_structure(odr, ptr, q->u.complex->s2, addinfo);
256         return e;
257     }
258     else if (q->which == Z_RPNStructure_simple)
259     {
260         if (q->u.simple->which == Z_Operand_APT)
261         {
262             return check_type_1_attributes(
263                 odr, ptr, q->u.simple->u.attributesPlusTerm->attributes,
264                 addinfo);
265         }
266     }
267     return 0;
268 }
269
270 int Yaz_ProxyConfig::check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
271                                   char **addinfo)
272 {
273     // possibly check for Bib-1
274     return check_type_1_structure(odr, ptr, query->RPNStructure, addinfo);
275 }
276
277 int Yaz_ProxyConfig::check_query(ODR odr, const char *name, Z_Query *query,
278                                  char **addinfo)
279 {
280     xmlNodePtr ptr;
281     
282     ptr = find_target_node(name);
283     if (ptr)
284     {
285         if (query->which == Z_Query_type_1 || query->which == Z_Query_type_101)
286             return check_type_1(odr, ptr, query->u.type_1, addinfo);
287     }
288     return 0;
289 }
290
291 xmlNodePtr Yaz_ProxyConfig::find_target_node(const char *name)
292 {
293     xmlNodePtr ptr;
294     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
295     {
296         if (ptr->type == XML_ELEMENT_NODE &&
297             !strcmp((const char *) ptr->name, "target"))
298         {
299             // default one ? 
300             if (!name)
301             {
302                 // <target default="1"> ?
303                 struct _xmlAttr *attr;
304                 for (attr = ptr->properties; attr; attr = attr->next)
305                     if (!strcmp((const char *) attr->name, "default") &&
306                         attr->children && attr->children->type == XML_TEXT_NODE)
307                     {
308                         xmlChar *t = attr->children->content;
309                         if (!t || *t == '1')
310                             return ptr;
311                     }
312             }
313             else
314             {
315                 // <target name="name"> ?
316                 struct _xmlAttr *attr;
317                 for (attr = ptr->properties; attr; attr = attr->next)
318                     if (!strcmp((const char *) attr->name, "name"))
319                     {
320                         if (attr->children
321                             && attr->children->type==XML_TEXT_NODE
322                             && attr->children->content 
323                             && (!strcmp((const char *) attr->children->content,
324                                         name)
325                                 || !strcmp((const char *) attr->children->content,
326                                            "*")))
327                         {
328                             return ptr;
329                         }
330                     }
331             }
332         }
333     }
334     return 0;
335 }
336
337
338 void Yaz_ProxyConfig::get_target_info(const char *name,
339                                       const char **url,
340                                       int *keepalive,
341                                       int *limit_bw,
342                                       int *limit_pdu,
343                                       int *limit_req,
344                                       int *target_idletime,
345                                       int *client_idletime,
346                                       int *max_clients)
347 {
348 #if HAVE_XML2
349     xmlNodePtr ptr;
350     if (!m_proxyPtr)
351     {
352         *url = name;
353         return;
354     }
355     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
356     {
357         if (ptr->type == XML_ELEMENT_NODE &&
358             !strcmp((const char *) ptr->name, "max-clients"))
359         {
360             const char *t = get_text(ptr);
361             if (t)
362             {
363                 *max_clients = atoi(t);
364                 if (*max_clients  < 1)
365                     *max_clients = 1;
366             }
367         }
368     }
369     ptr = find_target_node(name);
370     if (ptr)
371     {
372         if (name)
373             *url = name;
374         return_target_info(ptr, url, keepalive, limit_bw, limit_pdu, limit_req,
375                            target_idletime, client_idletime);
376     }
377 #else
378     *url = name;
379     return;
380 #endif
381 }
382
383