zoom: allow list of proxies for proxy parameter
[metaproxy-moved-to-github.git] / src / filter_zoom.cpp
index 39c02e6..45ead65 100644 (file)
@@ -120,7 +120,8 @@ namespace metaproxy_1 {
                                                   std::string &database,
                                                   int *error,
                                                   char **addinfo,
-                                                  ODR odr);
+                                                  ODR odr,
+                                                  int *proxy_step);
 
             bool create_content_session(mp::Package &package,
                                         BackendPtr b,
@@ -170,7 +171,8 @@ namespace metaproxy_1 {
             std::map<mp::Session, FrontendPtr> m_clients;            
             boost::mutex m_mutex;
             boost::condition m_cond_session_ready;
-            std::string torus_url;
+            std::string torus_searchable_url;
+            std::string torus_content_url;
             std::string default_realm;
             std::map<std::string,std::string> fieldmap;
             std::string xsldir;
@@ -572,7 +574,9 @@ void yf::Zoom::Impl::configure(const xmlNode *ptr, bool test_only,
             for (attr = ptr->properties; attr; attr = attr->next)
             {
                 if (!strcmp((const char *) attr->name, "url"))
-                    torus_url = mp::xml::get_text(attr->children);
+                    torus_searchable_url = mp::xml::get_text(attr->children);
+                else if (!strcmp((const char *) attr->name, "content_url"))
+                    torus_content_url = mp::xml::get_text(attr->children);
                 else if (!strcmp((const char *) attr->name, "realm"))
                     default_realm = mp::xml::get_text(attr->children);
                 else if (!strcmp((const char *) attr->name, "xsldir"))
@@ -588,6 +592,10 @@ void yf::Zoom::Impl::configure(const xmlNode *ptr, bool test_only,
                         "Bad attribute " + std::string((const char *)
                                                        attr->name));
             }
+            // If content_url is not given, use value of searchable, to
+            // ensure backwards compatibility
+            if (!torus_content_url.length())
+                torus_content_url = torus_searchable_url;
             configure_local_records(ptr->children, test_only);
         }
         else if (!strcmp((const char *) ptr->name, "cclmap"))
@@ -702,7 +710,8 @@ bool yf::Zoom::Frontend::create_content_session(mp::Package &package,
 
 yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
     mp::Package &package,
-    std::string &database, int *error, char **addinfo, ODR odr)
+    std::string &database, int *error, char **addinfo, ODR odr,
+    int *proxy_step)
 {
     std::list<BackendPtr>::const_iterator map_it;
     if (m_backend && m_backend->m_frontend_database == database)
@@ -722,6 +731,7 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
     std::string authentication;
     std::string content_authentication;
     std::string proxy;
+    std::string content_proxy;
     std::string realm = m_p->default_realm;
 
     const char *param_user = 0;
@@ -742,6 +752,8 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
     const char **out_values = (const char **)
         odr_malloc(odr, (10 + no_parms) * sizeof(*out_values));
     
+    // may be changed if it's a content connection
+    std::string torus_url = m_p->torus_searchable_url;
     int i;
     for (i = 0; i < no_parms; i++)
     {
@@ -757,12 +769,29 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
             param_content_user = value;
         else if (!strcmp(name, "content-password"))
             param_content_password = value;
+        else if (!strcmp(name, "content-proxy"))
+            content_proxy = value;
         else if (!strcmp(name, "proxy"))
-            proxy = value;
+        {
+            char **dstr;
+            int dnum = 0;
+            nmem_strsplit(odr->mem, ",", value, &dstr, &dnum);
+            if (*proxy_step >= dnum)
+                *proxy_step = 0;
+            else
+            {
+                proxy = dstr[*proxy_step];
+                
+                (*proxy_step)++;
+                if (*proxy_step == dnum)
+                    *proxy_step = 0;
+            }
+        }
         else if (!strcmp(name, "cproxysession"))
         {
             out_names[no_out_args] = name;
             out_values[no_out_args++] = value;
+            torus_url = m_p->torus_content_url;
         }
         else if (!strcmp(name, "realm"))
             realm = value;
@@ -799,11 +828,10 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
     it = m_p->s_map.find(torus_db);
     if (it != m_p->s_map.end())
         sptr = it->second;
-    else if (m_p->torus_url.length() > 0)
+    else if (torus_url.length() > 0)
     {
-        xmlDoc *doc = mp::get_searchable(package,
-                                         m_p->torus_url, torus_db, realm,
-                                         m_p->proxy);
+        xmlDoc *doc = mp::get_searchable(package,torus_url, torus_db,
+                                         realm, m_p->proxy);
         if (!doc)
         {
             *error = YAZ_BIB1_DATABASE_DOES_NOT_EXIST;
@@ -989,6 +1017,9 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
         if (proxy.length())
             b->set_option("proxy", proxy);
     }
+    if (proxy.length())
+        package.log("zoom", YLOG_LOG, "proxy: %s", proxy.c_str());
+                
     std::string url;
     if (sptr->sru.length())
     {
@@ -1016,7 +1047,8 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
     if (*error == 0)
         create_content_session(package, b, error, addinfo, odr,
                                content_authentication.length() ?
-                               content_authentication : authentication, proxy);
+                               content_authentication : authentication,
+                               content_proxy.length() ? content_proxy : proxy);
     if (*error == 0)
         m_backend = b;
     return b;
@@ -1380,11 +1412,22 @@ void yf::Zoom::Frontend::handle_search(mp::Package &package)
         return;
     }
 
+    int proxy_step = 0;
+
+next_proxy:
+
     int error = 0;
     char *addinfo = 0;
     std::string db(sr->databaseNames[0]);
+
     BackendPtr b = get_backend_from_databases(package, db, &error,
-                                              &addinfo, odr);
+                                              &addinfo, odr, &proxy_step);
+    if (error && proxy_step)
+    {
+        package.log("zoom", YLOG_WARN,
+                    "create backend failed: trying next proxy");
+        goto next_proxy;
+    }
     if (error)
     {
         log_diagnostic(package, error, addinfo);
@@ -1622,6 +1665,14 @@ void yf::Zoom::Frontend::handle_search(mp::Package &package)
         wrbuf_destroy(pqf_wrbuf);
     }
 
+    if (error && proxy_step)
+    {
+        // reset below prevent reuse in get_backend_from_databases
+        m_backend.reset();
+        package.log("zoom", YLOG_WARN, "search failed: trying next proxy");
+        goto next_proxy;
+    }
+
     const char *element_set_name = 0;
     Odr_int number_to_present = 0;
     if (!error)