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