Fix query handling (avoid bad type: SRW_query)
[metaproxy-moved-to-github.git] / src / filter_sru_to_z3950.cpp
index bb39765..5ae4f7e 100644 (file)
@@ -1,5 +1,5 @@
 /* This file is part of Metaproxy.
-   Copyright (C) 2005-2008 Index Data
+   Copyright (C) 2005-2009 Index Data
 
 Metaproxy is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
@@ -16,6 +16,9 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
 
+// make std::min actually work on Windows
+#define NOMINMAX 1
+
 #include "config.hpp"
 #include "filter.hpp"
 #include "package.hpp"
@@ -29,8 +32,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include <yaz/srw.h>
 #include <yaz/pquery.h>
 #include <yaz/oid_db.h>
+#include <yaz/log.h>
 
 #include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
 
 #include <iostream>
 #include <sstream>
@@ -49,19 +54,25 @@ namespace metaproxy_1 {
             void configure(const xmlNode *xmlnode);
             void process(metaproxy_1::Package &package);
         private:
-            union SRW_query {char * cql; char * xcql; char * pqf;};
-            typedef const int& SRW_query_type;
             std::map<std::string, const xmlNode *> m_database_explain;
-        private:
 
+            typedef std::map<std::string, int> ActiveUrlMap;
+
+            boost::mutex m_mutex;
+            boost::condition m_cond_url_ready;
+            ActiveUrlMap m_active_urls;
+        private:
+            void sru(metaproxy_1::Package &package, Z_GDU *zgdu_req);
             bool z3950_build_query(mp::odr &odr_en, Z_Query *z_query, 
-                                   const SRW_query &query, 
-                                   SRW_query_type query_type) const;
+                                   const Z_SRW_searchRetrieveRequest *req
+                                   ) const;
 
             bool z3950_init_request(mp::Package &package, 
                                     mp::odr &odr_en,
                                     std::string zurl,
-                                    Z_SRW_PDU *sru_pdu_res) const;
+                                    Z_SRW_PDU *sru_pdu_res,
+                                    const Z_SRW_PDU *sru_pdu_req
+                ) const;
 
             bool z3950_close_request(mp::Package &package) const;
 
@@ -91,6 +102,8 @@ namespace metaproxy_1 {
             int z3950_to_srw_diag(mp::odr &odr_en, 
                                   Z_SRW_searchRetrieveResponse *srw_res,
                                   Z_DefaultDiagFormat *ddf) const;
+
+
         };
     }
 }
@@ -144,18 +157,8 @@ void yf::SRUtoZ3950::Impl::configure(const xmlNode *confignode)
     }
 }
 
-void yf::SRUtoZ3950::Impl::process(mp::Package &package)
+void yf::SRUtoZ3950::Impl::sru(mp::Package &package, Z_GDU *zgdu_req)
 {
-    Z_GDU *zgdu_req = package.request().get();
-
-    // ignoring all non HTTP_Request packages
-    if (!zgdu_req || !(zgdu_req->which == Z_GDU_HTTP_Request)){
-        package.move();
-        return;
-    }
-    
-    // only working on  HTTP_Request packages now
-
     bool ok = true;    
 
     mp::odr odr_de(ODR_DECODE);
@@ -217,6 +220,10 @@ void yf::SRUtoZ3950::Impl::process(mp::Package &package)
         {
             zurl = std::string(arg->value);
         }
+        else if (!strcmp(arg->name, "x-max-sockets"))
+        {
+            package.origin().set_max_sockets(atoi(arg->value));
+        }
 
 
     // filter acts as sink for SRU explain requests
@@ -240,7 +247,8 @@ void yf::SRUtoZ3950::Impl::process(mp::Package &package)
         ok = mp_util::check_sru_query_exists(package, odr_en, 
                                              sru_pdu_res, sr_req);
 
-        if (ok && z3950_init_request(package, odr_en, zurl, sru_pdu_res))
+        if (ok && z3950_init_request(package, odr_en,
+                                     zurl, sru_pdu_res, sru_pdu_req))
         {
             ok = z3950_search_request(package, odr_en,
                                       sru_pdu_res, sr_req, zurl);
@@ -274,7 +282,8 @@ void yf::SRUtoZ3950::Impl::process(mp::Package &package)
                                YAZ_SRW_UNSUPP_OPERATION, "scan");
  
         // to be used when we do scan
-        if (false && z3950_init_request(package, odr_en, zurl, sru_pdu_res))
+        if (false && z3950_init_request(package, odr_en, zurl, sru_pdu_res,
+                                        sru_pdu_req))
         {
             z3950_scan_request(package, odr_en, sru_pdu_res, sr_req);    
             z3950_close_request(package);
@@ -295,12 +304,56 @@ void yf::SRUtoZ3950::Impl::process(mp::Package &package)
 }
 
 
+void yf::SRUtoZ3950::Impl::process(mp::Package &package)
+{
+    Z_GDU *zgdu_req = package.request().get();
+
+    // ignoring all non HTTP_Request packages
+    if (!zgdu_req || !(zgdu_req->which == Z_GDU_HTTP_Request)){
+        package.move();
+        return;
+    }
+    
+    // only working on HTTP_Request packages now
+
+    // see if HTTP request is already being executed..
+    // we consider only the SRU - GET case..
+    if (zgdu_req->u.HTTP_Request->content_len == 0)
+    {
+        const char *path = zgdu_req->u.HTTP_Request->path;
+        boost::mutex::scoped_lock lock(m_mutex);
+        while (1)
+        {
+            ActiveUrlMap::iterator it = m_active_urls.find(path);
+            if (it == m_active_urls.end())
+            {
+                m_active_urls[path] = 1;
+                break;
+            }
+            yaz_log(YLOG_LOG, "Waiting for %s to complete", path);
+            m_cond_url_ready.wait(lock);
+        }
+    }
+    sru(package, zgdu_req);
+    if (zgdu_req->u.HTTP_Request->content_len == 0)
+    {
+        const char *path = zgdu_req->u.HTTP_Request->path;
+        boost::mutex::scoped_lock lock(m_mutex);
+
+        ActiveUrlMap::iterator it = m_active_urls.find(path);
+
+        m_active_urls.erase(it);
+        m_cond_url_ready.notify_all();
+    }
+}
+
 
 bool 
 yf::SRUtoZ3950::Impl::z3950_init_request(mp::Package &package, 
                                          mp::odr &odr_en,
                                          std::string zurl,
-                                         Z_SRW_PDU *sru_pdu_res) const
+                                         Z_SRW_PDU *sru_pdu_res,
+                                         const Z_SRW_PDU *sru_pdu_req) const
 {
     // prepare Z3950 package
     Package z3950_package(package.session(), package.origin());
@@ -309,6 +362,7 @@ yf::SRUtoZ3950::Impl::z3950_init_request(mp::Package &package,
     // set initRequest APDU
     Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_initRequest);
     Z_InitRequest *init_req = apdu->u.initRequest;
+
     //TODO: add user name in apdu
     //TODO: add user passwd in apdu
     //init_req->idAuthentication = org_init->idAuthentication;
@@ -427,9 +481,7 @@ bool yf::SRUtoZ3950::Impl::z3950_search_request(mp::Package &package,
     Z_Query *z_query = (Z_Query *) odr_malloc(odr_en, sizeof(Z_Query));
     z_searchRequest->query = z_query;
  
-    if (!z3950_build_query(odr_en, z_query, 
-                           (const SRW_query&)sr_req->query, 
-                           sr_req->query_type))
+    if (!z3950_build_query(odr_en, z_query, sr_req))
     {    
         yaz_add_srw_diagnostic(odr_en,
                                &(sru_pdu_res->u.response->diagnostics), 
@@ -770,10 +822,10 @@ yf::SRUtoZ3950::Impl::z3950_scan_request(mp::Package &package,
 }
 
 bool yf::SRUtoZ3950::Impl::z3950_build_query(mp::odr &odr_en, Z_Query *z_query, 
-                                            const SRW_query &query, 
-                                            SRW_query_type query_type) const
+                                             const Z_SRW_searchRetrieveRequest *req
+    ) const
 {        
-    if (query_type == Z_SRW_query_type_cql)
+    if (req->query_type == Z_SRW_query_type_cql)
     {
         Z_External *ext = (Z_External *) 
             odr_malloc(odr_en, sizeof(*ext));
@@ -782,21 +834,21 @@ bool yf::SRUtoZ3950::Impl::z3950_build_query(mp::odr &odr_en, Z_Query *z_query,
         ext->indirect_reference = 0;
         ext->descriptor = 0;
         ext->which = Z_External_CQL;
-        ext->u.cql = const_cast<char *>(query.cql);
+        ext->u.cql = odr_strdup(odr_en, req->query.cql);
         
         z_query->which = Z_Query_type_104;
         z_query->u.type_104 =  ext;
         return true;
     }
 
-    if (query_type == Z_SRW_query_type_pqf)
+    if (req->query_type == Z_SRW_query_type_pqf)
     {
         Z_RPNQuery *RPNquery;
         YAZ_PQF_Parser pqf_parser;
         
         pqf_parser = yaz_pqf_create ();
         
-        RPNquery = yaz_pqf_parse (pqf_parser, odr_en, query.pqf);
+        RPNquery = yaz_pqf_parse (pqf_parser, odr_en, req->query.pqf);
         if (!RPNquery)
         {
             std::cout << "TODO: Handeling of bad PQF\n";
@@ -865,8 +917,9 @@ extern "C" {
 /*
  * Local variables:
  * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
  * indent-tabs-mode: nil
- * c-file-style: "stroustrup"
  * End:
  * vim: shiftwidth=4 tabstop=8 expandtab
  */
+