z3950_client: don't tamper with target zurl
[metaproxy-moved-to-github.git] / src / filter_z3950_client.cpp
index 06f58e1..b988728 100644 (file)
@@ -1,5 +1,5 @@
 /* This file is part of Metaproxy.
-   Copyright (C) 2005-2011 Index Data
+   Copyright (C) 2005-2012 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
@@ -55,6 +55,8 @@ namespace metaproxy_1 {
             void failNotify();
             void timeoutNotify();
             void recv_GDU(Z_GDU *gdu, int len);
+            void fixup_nsd(ODR odr, Z_Records *records);
+            void fixup_init(ODR odr, Z_InitResponse *initrs);
             yazpp_1::IPDU_Observer* sessionNotify(
                 yazpp_1::IPDU_Observable *the_PDU_Observable,
                 int fd);
@@ -168,12 +170,100 @@ void yf::Z3950Client::Assoc::timeoutNotify()
     }
 }
 
+void yf::Z3950Client::Assoc::fixup_nsd(ODR odr, Z_Records *records)
+{
+    if (records && records->which == Z_Records_NSD)
+    {
+        Z_DefaultDiagFormat *nsd = records->u.nonSurrogateDiagnostic;
+       std::string addinfo;
+        
+        // should really check for nsd->which.. But union has two members
+        // containing almost same data
+        const char *v2Addinfo = nsd->u.v2Addinfo;
+       //  Z_InternationalString *v3Addinfo;
+
+        if (v2Addinfo && *v2Addinfo)
+        {
+            addinfo.assign(nsd->u.v2Addinfo);
+            addinfo += " ";
+        }
+        addinfo += "(backend=" + m_host + ")";
+        nsd->u.v2Addinfo = odr_strdup(odr, addinfo.c_str());
+    }
+}
+
+void yf::Z3950Client::Assoc::fixup_init(ODR odr, Z_InitResponse *initrs)
+{
+    Z_External *uif = initrs->userInformationField;
+
+    if (uif && uif->which == Z_External_userInfo1)
+    {
+        Z_OtherInformation *ui = uif->u.userInfo1;
+        int i;
+        for (i = 0; i < ui->num_elements; i++)
+        {
+            Z_OtherInformationUnit *unit = ui->list[i];
+            if (unit->which == Z_OtherInfo_externallyDefinedInfo &&
+                unit->information.externallyDefinedInfo &&
+                unit->information.externallyDefinedInfo->which ==
+                Z_External_diag1) 
+            {
+                Z_DiagnosticFormat *diag =
+                    unit->information.externallyDefinedInfo->u.diag1;
+                int j;
+                for (j = 0; j < diag->num; j++)
+                {
+                    Z_DiagnosticFormat_s *ds = diag->elements[j];
+                    if (ds->which == Z_DiagnosticFormat_s_defaultDiagRec)
+                    {
+                        Z_DefaultDiagFormat *r = ds->u.defaultDiagRec;
+                        char *oaddinfo = r->u.v2Addinfo;
+                        char *naddinfo = (char *) odr_malloc(
+                            odr,
+                            (oaddinfo ? strlen(oaddinfo) : 0) + 20 +
+                            m_host.length());
+                        if (oaddinfo && *oaddinfo)
+                        {
+                            strcpy(naddinfo, oaddinfo);
+                            strcat(naddinfo, " ");
+                        }
+                        strcat(naddinfo, "(backend=");
+                        strcat(naddinfo, m_host.c_str());
+                        strcat(naddinfo, ")");
+
+                        r->u.v2Addinfo = naddinfo;
+                    }
+                }
+            } 
+        }
+    }
+}
+
 void yf::Z3950Client::Assoc::recv_GDU(Z_GDU *gdu, int len)
 {
     m_waiting = false;
 
     if (m_package)
+    { 
+        mp::odr odr; // must be in scope for response() = assignment
+        if (gdu && gdu->which == Z_GDU_Z3950)
+        {
+            Z_APDU *apdu = gdu->u.z3950;
+            switch (apdu->which)
+            {
+            case Z_APDU_searchResponse:
+                fixup_nsd(odr, apdu->u.searchResponse->records);
+                break;
+            case Z_APDU_presentResponse:
+                fixup_nsd(odr, apdu->u.presentResponse->records);
+                break;
+            case Z_APDU_initResponse:
+                fixup_init(odr, apdu->u.initResponse);
+                break;
+            }
+        }
         m_package->response() = gdu;
+    }
 }
 
 yazpp_1::IPDU_Observer *yf::Z3950Client::Assoc::sessionNotify(
@@ -207,8 +297,6 @@ yf::Z3950Client::Assoc *yf::Z3950Client::Rep::get_assoc(Package &package)
     if (max_sockets == 0)
         max_sockets = m_max_sockets;
     
-    std::string host;
-
     it = m_clients.find(package.session());
     if (it != m_clients.end())
     {
@@ -294,14 +382,6 @@ yf::Z3950Client::Assoc *yf::Z3950Client::Rep::get_assoc(Package &package)
         }
     }
     
-    std::list<std::string> dblist;
-    mp::util::split_zurl(target, host, dblist);
-    
-    if (dblist.size())
-    {
-        ; // z3950_client: Databases in vhost ignored
-    }
-    
     // see if we have reached max number of clients (max-sockets)
 
     while (max_sockets)
@@ -312,7 +392,7 @@ yf::Z3950Client::Assoc *yf::Z3950Client::Rep::get_assoc(Package &package)
         for (; it != m_clients.end(); it++)
         {
             yf::Z3950Client::Assoc *as = it->second;
-            if (!strcmp(as->m_host.c_str(), host.c_str()))
+            if (!strcmp(as->m_host.c_str(), target.c_str()))
             {
                 number++;
                 if (!as->m_in_use)
@@ -320,7 +400,7 @@ yf::Z3950Client::Assoc *yf::Z3950Client::Rep::get_assoc(Package &package)
             }
         }
         yaz_log(YLOG_LOG, "Found %d/%d connections for %s", number, max_sockets,
-                host.c_str());
+                target.c_str());
         if (number < max_sockets)
             break;
         if (no_not_in_use == 0) // all in use..
@@ -350,7 +430,7 @@ yf::Z3950Client::Assoc *yf::Z3950Client::Rep::get_assoc(Package &package)
     yazpp_1::SocketManager *sm = new yazpp_1::SocketManager;
     yazpp_1::PDU_Assoc *pdu_as = new yazpp_1::PDU_Assoc(sm);
     yf::Z3950Client::Assoc *as = new yf::Z3950Client::Assoc(sm, pdu_as,
-                                                            host.c_str(),
+                                                            target.c_str(),
                                                             m_timeout_sec);
     m_clients[package.session()] = as;
     return as;
@@ -386,8 +466,16 @@ void yf::Z3950Client::Rep::send_and_receive(Package &package,
     c->m_waiting = true;
     if (!c->m_connected)
     {
-        c->client(c->m_host.c_str());
+        if (c->client(c->m_host.c_str()))
+        {
+            mp::odr odr;
+            package.response() =
+                odr.create_close(gdu->u.z3950, Z_Close_peerAbort, 0);
+            package.session().close();
+            return;
+        }
         c->timeout(1);  // so timeoutNotify gets called once per second
+        
 
         while (!c->m_destroyed && c->m_waiting 
                && c->m_socket_manager->processEvent() > 0)
@@ -457,7 +545,8 @@ void yf::Z3950Client::process(Package &package) const
     }
 }
 
-void yf::Z3950Client::configure(const xmlNode *ptr, bool test_only)
+void yf::Z3950Client::configure(const xmlNode *ptr, bool test_only,
+                                const char *path)
 {
     for (ptr = ptr->children; ptr; ptr = ptr->next)
     {