User-defined error handling for queries in proxy
authorAdam Dickmeiss <adam@indexdata.dk>
Fri, 3 Oct 2003 13:01:42 +0000 (13:01 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Fri, 3 Oct 2003 13:01:42 +0000 (13:01 +0000)
include/yaz++/proxy.h
include/yaz++/z-query.h
src/yaz-proxy-config.cpp
src/yaz-proxy.cpp
src/yaz-z-query.cpp

index dd86def..c40a13d 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 1998-2003, Index Data.
  * See the file LICENSE for details.
  * 
- * $Id: proxy.h,v 1.8 2003-10-01 13:13:51 adam Exp $
+ * $Id: proxy.h,v 1.9 2003-10-03 13:01:42 adam Exp $
  */
 
 #include <yaz++/z-assoc.h>
@@ -24,17 +24,29 @@ public:
     ~Yaz_ProxyConfig();
     int read_xml(const char *fname);
     void get_target_info(const char *name, const char **url, int *keepalive,
-                        int *limit_bw, int *limit_pdu, int *limit_req);
+                        int *limit_bw, int *limit_pdu, int *limit_req,
+                        int *target_idletime, int *client_idletime,
+                        int *max_clients);
     void operator=(const Yaz_ProxyConfig &conf);
+    int check_query(ODR odr, const char *name, Z_Query *query, char **addinfo);
 private:
 #if HAVE_XML2
     xmlDocPtr m_docPtr;
     xmlNodePtr m_proxyPtr;
     void return_target_info(xmlNodePtr ptr, const char **url, int *keepalive,
-                           int *limit_bw, int *limit_pdu, int *limit_req);
+                           int *limit_bw, int *limit_pdu, int *limit_req,
+                           int *target_idletime, int *client_idletime);
     void return_limit(xmlNodePtr ptr,
                      int *limit_bw, int *limit_pdu, int *limit_req);
+    int check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
+                    char **addinfo);
+    xmlNodePtr find_target_node(const char *name);
     const char *get_text(xmlNodePtr ptr);
+    int check_type_1_attributes(ODR odr, xmlNodePtr ptr,
+                               Z_AttributeList *attrs,
+                               char **addinfo);
+    int check_type_1_structure(ODR odr, xmlNodePtr ptr, Z_RPNStructure *q,
+                              char **addinfo);
 #endif
     int m_copy;
 };
@@ -145,6 +157,10 @@ class YAZ_EXPORT Yaz_Proxy : public Yaz_Z_Assoc {
     int m_max_record_retrieve;
     void handle_max_record_retrieve(Z_APDU *apdu);
     void display_diagrecs(Z_DiagRec **pp, int num);
+    Z_Records *create_nonSurrogateDiagnostics(ODR o, int error,
+                                             const char *addinfo);
+
+    Z_APDU *handle_query_validation(Z_APDU *apdu);
  public:
     Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable);
     ~Yaz_Proxy();
index 57a2c44..3367769 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 1998-2000, Index Data.
  * See the file LICENSE for details.
  * 
- * $Id: z-query.h,v 1.2 2003-10-01 13:13:51 adam Exp $
+ * $Id: z-query.h,v 1.3 2003-10-03 13:01:42 adam Exp $
  */
 
 #include <yaz/proto.h>
@@ -28,8 +28,8 @@ class YAZ_EXPORT Yaz_Z_Query : public Yaz_Query {
     /// match query
     int match(Yaz_Z_Query *other);
  private:
-    char *buf;
-    int len;
+    char *m_buf;
+    int m_len;
     ODR odr_decode;
     ODR odr_encode;
     ODR odr_print;
index 61cfb8d..329a037 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 1998-2003, Index Data.
  * See the file LICENSE for details.
  * 
- * $Id: yaz-proxy-config.cpp,v 1.1 2003-10-01 13:13:51 adam Exp $
+ * $Id: yaz-proxy-config.cpp,v 1.2 2003-10-03 13:01:42 adam Exp $
  */
 
 #include <yaz/log.h>
@@ -121,7 +121,9 @@ void Yaz_ProxyConfig::return_target_info(xmlNodePtr ptr,
                                         int *keepalive,
                                         int *limit_bw,
                                         int *limit_pdu,
-                                        int *limit_req)
+                                        int *limit_req,
+                                        int *target_idletime,
+                                        int *client_idletime)
 {
     ptr = ptr->children;
     for (; ptr; ptr = ptr->next)
@@ -145,24 +147,150 @@ void Yaz_ProxyConfig::return_target_info(xmlNodePtr ptr,
        if (ptr->type == XML_ELEMENT_NODE 
            && !strcmp((const char *) ptr->name, "limit"))
            return_limit(ptr, limit_bw, limit_pdu, limit_req);
+       if (ptr->type == XML_ELEMENT_NODE 
+           && !strcmp((const char *) ptr->name, "target-timeout"))
+       {
+           const char *t = get_text(ptr);
+           if (t)
+           {
+               *target_idletime = atoi(t);
+               if (*target_idletime < 0)
+                   *target_idletime = 0;
+           }
+       }
+       if (ptr->type == XML_ELEMENT_NODE 
+           && !strcmp((const char *) ptr->name, "client-timeout"))
+       {
+           const char *t = get_text(ptr);
+           if (t)
+           {
+               *client_idletime = atoi(t);
+               if (*client_idletime < 0)
+                   *client_idletime = 0;
+           }
+       }
     }
 }
 #endif
 
-void Yaz_ProxyConfig::get_target_info(const char *name,
-                                     const char **url,
-                                     int *keepalive,
-                                     int *limit_bw,
-                                     int *limit_pdu,
-                                     int *limit_req)
+int Yaz_ProxyConfig::check_type_1_attributes(ODR odr, xmlNodePtr ptr,
+                                            Z_AttributeList *attrs,
+                                            char **addinfo)
+{
+    for(ptr = ptr->children; ptr; ptr = ptr->next)
+    {
+       if (ptr->type == XML_ELEMENT_NODE &&
+           !strcmp((const char *) ptr->name, "query"))
+       {
+           const char *match_type = 0;
+           const char *match_value = 0;
+           const char *match_error = 0;
+           struct _xmlAttr *attr;
+           for (attr = ptr->properties; attr; attr = attr->next)
+           {
+               if (!strcmp((const char *) attr->name, "type") &&
+                   attr->children && attr->children->type == XML_TEXT_NODE)
+                   match_type = (const char *) attr->children->content;
+               if (!strcmp((const char *) attr->name, "value") &&
+                   attr->children && attr->children->type == XML_TEXT_NODE)
+                   match_value = (const char *) attr->children->content;
+               if (!strcmp((const char *) attr->name, "error") &&
+                   attr->children && attr->children->type == XML_TEXT_NODE)
+                   match_error = (const char *) attr->children->content;
+           }
+           int i;
+
+           if (match_type && match_value)
+           {
+               for (i = 0; i<attrs->num_attributes; i++)
+               {
+                   Z_AttributeElement *el = attrs->attributes[i];
+                   char value_str[20];
+                   
+                   value_str[0] = '\0';
+                   if (!el->attributeType)
+                       continue;
+                   int type = *el->attributeType;
+
+                   if (strcmp(match_type, "*")) {
+                       if (type != atoi(match_type))
+                           continue;  // no match on type
+                   }
+                   if (el->which == Z_AttributeValue_numeric && 
+                       el->value.numeric)
+                   {
+                       int value = *el->value.numeric;
+                       if (strcmp(match_value, "*")) {
+                           if (value != atoi(match_value))
+                               continue;  // no match on value
+                       }
+                       sprintf(value_str, "%d", value);
+                   }
+                   else
+                       continue;
+                   if (match_error)
+                   {
+                       if (*value_str)
+                           *addinfo = odr_strdup(odr, value_str);
+                       return atoi(match_error);
+                   }
+                   return 0;
+               }
+           }
+       }
+    }
+    return 0;
+}
+
+int Yaz_ProxyConfig::check_type_1_structure(ODR odr, xmlNodePtr ptr,
+                                           Z_RPNStructure *q,
+                                           char **addinfo)
+{
+    int c;
+    if (q->which == Z_RPNStructure_complex)
+    {
+       int e = check_type_1_structure(odr, ptr, q->u.complex->s1, addinfo);
+       if (e)
+           return e;
+       e = check_type_1_structure(odr, ptr, q->u.complex->s2, addinfo);
+       return e;
+    }
+    else if (q->which == Z_RPNStructure_simple)
+    {
+       if (q->u.simple->which == Z_Operand_APT)
+       {
+           return check_type_1_attributes(
+               odr, ptr, q->u.simple->u.attributesPlusTerm->attributes,
+               addinfo);
+       }
+    }
+    return 0;
+}
+
+int Yaz_ProxyConfig::check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
+                                 char **addinfo)
+{
+    // possibly check for Bib-1
+    return check_type_1_structure(odr, ptr, query->RPNStructure, addinfo);
+}
+
+int Yaz_ProxyConfig::check_query(ODR odr, const char *name, Z_Query *query,
+                                char **addinfo)
 {
-#if HAVE_XML2
     xmlNodePtr ptr;
-    if (!m_proxyPtr)
+    
+    ptr = find_target_node(name);
+    if (ptr)
     {
-       *url = name;
-       return;
+       if (query->which == Z_Query_type_1 || query->which == Z_Query_type_101)
+           return check_type_1(odr, ptr, query->u.type_1, addinfo);
     }
+    return 0;
+}
+
+xmlNodePtr Yaz_ProxyConfig::find_target_node(const char *name)
+{
+    xmlNodePtr ptr;
     for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
     {
        if (ptr->type == XML_ELEMENT_NODE &&
@@ -179,11 +307,7 @@ void Yaz_ProxyConfig::get_target_info(const char *name,
                    {
                        xmlChar *t = attr->children->content;
                        if (!t || *t == '1')
-                       {
-                           return_target_info(ptr, url, keepalive,
-                                              limit_bw, limit_pdu, limit_req);
-                           return;
-                       }
+                           return ptr;
                    }
            }
            else
@@ -201,15 +325,55 @@ void Yaz_ProxyConfig::get_target_info(const char *name,
                                || !strcmp((const char *) attr->children->content,
                                           "*")))
                        {
-                           *url = name;
-                           return_target_info(ptr, url, keepalive,
-                                              limit_bw, limit_pdu, limit_req);
-                           return;
+                           return ptr;
                        }
                    }
            }
        }
     }
+    return 0;
+}
+
+
+void Yaz_ProxyConfig::get_target_info(const char *name,
+                                     const char **url,
+                                     int *keepalive,
+                                     int *limit_bw,
+                                     int *limit_pdu,
+                                     int *limit_req,
+                                     int *target_idletime,
+                                     int *client_idletime,
+                                     int *max_clients)
+{
+#if HAVE_XML2
+    xmlNodePtr ptr;
+    if (!m_proxyPtr)
+    {
+       *url = name;
+       return;
+    }
+    for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
+    {
+       if (ptr->type == XML_ELEMENT_NODE &&
+           !strcmp((const char *) ptr->name, "max-clients"))
+       {
+           const char *t = get_text(ptr);
+           if (t)
+           {
+               *max_clients = atoi(t);
+               if (*max_clients  < 1)
+                   *max_clients = 1;
+           }
+       }
+    }
+    ptr = find_target_node(name);
+    if (ptr)
+    {
+       if (name)
+           *url = name;
+       return_target_info(ptr, url, keepalive, limit_bw, limit_pdu, limit_req,
+                          target_idletime, client_idletime);
+    }
 #else
     *url = name;
     return;
index 81e987e..1390f96 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 1998-2003, Index Data.
  * See the file LICENSE for details.
  * 
- * $Id: yaz-proxy.cpp,v 1.48 2003-10-01 13:13:51 adam Exp $
+ * $Id: yaz-proxy.cpp,v 1.49 2003-10-03 13:01:42 adam Exp $
  */
 
 #include <assert.h>
@@ -50,7 +50,6 @@ static const char *apdu_name(Z_APDU *apdu)
     return "other";
 }
 
-
 Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable) :
     Yaz_Z_Assoc(the_PDU_Observable), m_bw_stat(60), m_pdu_stat(60)
 {
@@ -173,12 +172,23 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu)
     {
        const char *proxy_host = get_proxy(oi);
        if (!proxy_host)
+       {
+           xfree(m_default_target);
+           m_default_target = xstrdup(proxy_host);
            proxy_host = m_default_target;
+       }
        
        const char *url = 0;
+       int client_idletime = -1;
        m_config.get_target_info(proxy_host, &url, &m_keepalive, &m_bw_max,
-                                &m_pdu_max, &m_max_record_retrieve);
-       
+                                &m_pdu_max, &m_max_record_retrieve,
+                                &m_target_idletime, &client_idletime,
+                                &parent->m_max_clients);
+       if (client_idletime != -1)
+       {
+           m_client_idletime = client_idletime;
+           timeout(m_client_idletime);
+       }
        if (!url)
        {
            yaz_log(LOG_LOG, "%s No default target", m_session_str);
@@ -724,6 +734,57 @@ void Yaz_Proxy::handle_max_record_retrieve(Z_APDU *apdu)
     }
 }
 
+Z_Records *Yaz_Proxy::create_nonSurrogateDiagnostics(ODR odr,
+                                                    int error,
+                                                    const char *addinfo)
+{
+    Z_Records *rec = (Z_Records *)
+        odr_malloc (odr, sizeof(*rec));
+    int *err = (int *)
+        odr_malloc (odr, sizeof(*err));
+    Z_DiagRec *drec = (Z_DiagRec *)
+        odr_malloc (odr, sizeof(*drec));
+    Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
+        odr_malloc (odr, sizeof(*dr));
+    *err = error;
+    rec->which = Z_Records_NSD;
+    rec->u.nonSurrogateDiagnostic = dr;
+    dr->diagnosticSetId =
+        yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
+    dr->condition = err;
+    dr->which = Z_DefaultDiagFormat_v2Addinfo;
+    dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
+    return rec;
+}
+
+Z_APDU *Yaz_Proxy::handle_query_validation(Z_APDU *apdu)
+{
+    if (apdu->which == Z_APDU_searchRequest)
+    {
+       Z_SearchRequest *sr = apdu->u.searchRequest;
+       int err;
+       char *addinfo = 0;
+       err = m_config.check_query(odr_encode(), m_default_target, sr->query,
+                                  &addinfo);
+       if (err)
+       {
+           Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+           int *nulint = odr_intdup (odr_encode(), 0);
+
+           new_apdu->u.searchResponse->referenceId = sr->referenceId;
+           new_apdu->u.searchResponse->records =
+               create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
+           new_apdu->u.searchResponse->searchStatus = nulint;
+           new_apdu->u.searchResponse->resultCount = nulint;
+
+           send_to_client(new_apdu);
+
+           return 0;
+       }
+    }
+    return apdu;
+}
+
 void Yaz_Proxy::recv_Z_PDU_0(Z_APDU *apdu)
 {
     // Determine our client.
@@ -751,9 +812,17 @@ void Yaz_Proxy::recv_Z_PDU_0(Z_APDU *apdu)
     }
     handle_max_record_retrieve(apdu);
 
-    apdu = result_set_optimize(apdu);
+    if (apdu)
+       apdu = handle_query_validation(apdu);
+
+    if (apdu)
+       apdu = result_set_optimize(apdu);
     if (!apdu)
+    {
+       m_client->timeout(m_target_idletime);  // mark it active even 
+       // though we didn't use it
        return;
+    }
 
     // delete other info part from PDU before sending to target
     Z_OtherInformation **oi;
@@ -944,6 +1013,21 @@ void Yaz_ProxyClient::recv_Z_PDU(Z_APDU *apdu, int len)
        odr_reset (m_init_odr);
         nmem_transfer (m_init_odr->mem, nmem);
         m_initResponse = apdu;
+
+       Z_InitResponse *ir = apdu->u.initResponse;
+       char *im0 = ir->implementationName;
+       
+       char *im1 = (char*) 
+           odr_malloc(m_init_odr, 20 + (im0 ? strlen(im0) : 0));
+       *im1 = '\0';
+       if (im0)
+       {
+           strcat(im1, im0);
+           strcat(im1, " ");
+       }
+       strcat(im1, "(YAZ Proxy)");
+       ir->implementationName = im1;
+
         nmem_destroy (nmem);
     }
     if (apdu->which == Z_APDU_searchResponse)
@@ -978,7 +1062,8 @@ void Yaz_ProxyClient::recv_Z_PDU(Z_APDU *apdu, int len)
            sr->numberOfRecordsReturned = pr->numberOfRecordsReturned;
            apdu = new_apdu;
        }
-       if (pr->records->which == Z_Records_DBOSD && m_resultSetStartPoint)
+       if (pr->records && 
+           pr->records->which == Z_Records_DBOSD && m_resultSetStartPoint)
        {
            m_cache.add(odr_decode(),
                        pr->records->u.databaseOrSurDiagnostics,
index c0bed5e..8d391d5 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 1998-2003, Index Data.
  * See the file LICENSE for details.
  * 
- * $Id: yaz-z-query.cpp,v 1.12 2003-10-01 13:13:51 adam Exp $
+ * $Id: yaz-z-query.cpp,v 1.13 2003-10-03 13:01:42 adam Exp $
  */
 
 #include <yaz++/z-query.h>
@@ -17,7 +17,7 @@ Yaz_Z_Query::Yaz_Z_Query()
 
 int Yaz_Z_Query::set_rpn (const char *rpn)
 {
-    buf = 0;
+    m_buf = 0;
     odr_reset (odr_encode);
     Z_Query *query = (Z_Query*) odr_malloc (odr_encode, sizeof(*query));
     query->which = Z_Query_type_1;
@@ -27,17 +27,17 @@ int Yaz_Z_Query::set_rpn (const char *rpn)
     if (!z_Query (odr_encode, &query, 0, 0))
        return -1;
     // z_Query(odr_print, &query, 0, 0);
-    buf = odr_getbuf (odr_encode, &len, 0);
-    return len;
+    m_buf = odr_getbuf (odr_encode, &m_len, 0);
+    return m_len;
 }
 
 void Yaz_Z_Query::set_Z_Query(Z_Query *z_query)
 {
-    buf = 0;
+    m_buf = 0;
     odr_reset (odr_encode);
     if (!z_Query (odr_encode, &z_query, 0, 0))
        return;
-    buf = odr_getbuf (odr_encode, &len, 0);
+    m_buf = odr_getbuf (odr_encode, &m_len, 0);
 }
 
 Yaz_Z_Query::~Yaz_Z_Query()
@@ -50,10 +50,10 @@ Yaz_Z_Query::~Yaz_Z_Query()
 Z_Query *Yaz_Z_Query::get_Z_Query ()
 {
     Z_Query *query;
-    if (!buf)
+    if (!m_buf)
        return 0;
     odr_reset(odr_decode);
-    odr_setbuf(odr_decode, buf, len, 0);
+    odr_setbuf(odr_decode, m_buf, m_len, 0);
     if (!z_Query(odr_decode, &query, 0, 0))
        return 0;
     return query;
@@ -63,9 +63,9 @@ void Yaz_Z_Query::print(char *str, int len)
 {
     Z_Query *query;
     *str = 0;
-    if (!buf)
+    if (!m_buf)
        return;
-    odr_setbuf (odr_decode, buf, len, 0);
+    odr_setbuf (odr_decode, m_buf, m_len, 0);
     if (!z_Query(odr_decode, &query, 0, 0))
        return;
     WRBUF wbuf = zquery2pquery(query);
@@ -85,11 +85,11 @@ void Yaz_Z_Query::print(char *str, int len)
 
 int Yaz_Z_Query::match(Yaz_Z_Query *other)
 {
-    if (len != other->len)
+    if (m_len != other->m_len)
        return 0;
-    if (!buf || !other->buf)
+    if (!m_buf || !other->m_buf)
        return 0;
-    if (memcmp(buf, other->buf, len))
+    if (memcmp(m_buf, other->m_buf, m_len))
        return 0;
     return 1;
 }