Add nocproxy=1 for contentConnector sessions MP-501
[metaproxy-moved-to-github.git] / src / filter_zoom.cpp
index 95e2b36..2a93af5 100644 (file)
@@ -1,5 +1,5 @@
 /* This file is part of Metaproxy.
-   Copyright (C) 2005-2012 Index Data
+   Copyright (C) 2005-2013 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
@@ -60,6 +60,7 @@ namespace metaproxy_1 {
         class Zoom::Searchable : boost::noncopyable {
           public:
             std::string authentication;
+            std::string authenticationMode;
             std::string cfAuth;
             std::string cfProxy;
             std::string cfSubDB;
@@ -107,7 +108,7 @@ namespace metaproxy_1 {
             void connect(std::string zurl, int *error, char **addinfo,
                          ODR odr);
             void search(ZOOM_query q, Odr_int *hits,
-                        int *error, char **addinfo, ODR odr);
+                        int *error, char **addinfo, Z_FacetList **fl, ODR odr);
             void present(Odr_int start, Odr_int number, ZOOM_record *recs,
                          int *error, char **addinfo, ODR odr);
             void set_option(const char *name, const char *value);
@@ -125,7 +126,6 @@ namespace metaproxy_1 {
             BackendPtr m_backend;
             void handle_package(mp::Package &package);
             void handle_search(mp::Package &package);
-
             void auth(mp::Package &package, Z_InitRequest *req,
                       int *error, char **addinfo, ODR odr);
 
@@ -370,15 +370,84 @@ void yf::Zoom::Backend::connect(std::string zurl,
 }
 
 void yf::Zoom::Backend::search(ZOOM_query q, Odr_int *hits,
-                               int *error, char **addinfo, ODR odr)
+                               int *error, char **addinfo, Z_FacetList **flp,
+                               ODR odr)
 {
     ZOOM_resultset_destroy(m_resultset);
+    m_resultset = 0;
+    if (*flp)
+    {
+        WRBUF w = wrbuf_alloc();
+        yaz_facet_list_to_wrbuf(w, *flp);
+        set_option("facets", wrbuf_cstr(w));
+        wrbuf_destroy(w);
+    }
     m_resultset = ZOOM_connection_search(m_connection, q);
     get_zoom_error(error, addinfo, odr);
     if (*error == 0)
         *hits = ZOOM_resultset_size(m_resultset);
     else
         *hits = 0;
+    *flp = 0;
+    size_t num_facets = ZOOM_resultset_facets_size(m_resultset);
+    if (num_facets > 0)
+    {
+        size_t i;
+        Z_FacetList *fl = (Z_FacetList *) odr_malloc(odr, sizeof(*fl));
+        fl->elements = (Z_FacetField **)
+            odr_malloc(odr, num_facets * sizeof(*fl->elements));
+        for (i = 0; i < num_facets; i++)
+        {
+            ZOOM_facet_field ff =
+                ZOOM_resultset_get_facet_field_by_index(m_resultset, i);
+            if (!ff)
+                break;
+            Z_AttributeList *al = (Z_AttributeList *)
+                odr_malloc(odr, sizeof(*al));
+            al->num_attributes = 1;
+            al->attributes = (Z_AttributeElement **)
+                odr_malloc(odr, sizeof(*al->attributes));
+            Z_AttributeElement *ae = al->attributes[0] = (Z_AttributeElement *)
+                odr_malloc(odr, sizeof(**al->attributes));
+            ae->attributeSet = 0;
+            ae->attributeType = odr_intdup(odr, 1);
+            ae->which = Z_AttributeValue_complex;
+            ae->value.complex = (Z_ComplexAttribute *)
+                odr_malloc(odr, sizeof(*ae->value.complex));
+            ae->value.complex->num_list = 1;
+            ae->value.complex->list = (Z_StringOrNumeric **)
+                odr_malloc(odr, sizeof(**ae->value.complex->list));
+            ae->value.complex->list[0] = (Z_StringOrNumeric *)
+                odr_malloc(odr, sizeof(**ae->value.complex->list));
+            ae->value.complex->list[0]->which = Z_StringOrNumeric_string;
+            ae->value.complex->list[0]->u.string =
+                odr_strdup(odr, ZOOM_facet_field_name(ff));
+            ae->value.complex->num_semanticAction = 0;
+            ae->value.complex->semanticAction = 0;
+
+            int num_terms = ZOOM_facet_field_term_count(ff);
+            fl->elements[i] = (Z_FacetField *)
+                odr_malloc(odr, sizeof(Z_FacetField));
+            fl->elements[i]->attributes = al;
+            fl->elements[i]->num_terms = num_terms;
+            fl->elements[i]->terms = (Z_FacetTerm **)
+                odr_malloc(odr, num_terms * sizeof(Z_FacetTerm *));
+            int j;
+            for (j = 0; j < num_terms; j++)
+            {
+                int freq;
+                const char *a_term = ZOOM_facet_field_get_term(ff, j, &freq);
+                Z_FacetTerm *ft = (Z_FacetTerm *) odr_malloc(odr, sizeof(*ft));
+                ft->term = z_Term_create(odr, Z_Term_general, a_term,
+                                         strlen(a_term));
+                ft->count = odr_intdup(odr, freq);
+
+                fl->elements[i]->terms[j] = ft;
+            }
+        }
+        fl->num = i;
+        *flp = fl;
+    }
 }
 
 void yf::Zoom::Backend::present(Odr_int start, Odr_int number,
@@ -508,6 +577,11 @@ yf::Zoom::SearchablePtr yf::Zoom::Impl::parse_torus_record(const xmlNode *ptr)
             s->authentication = mp::xml::get_text(ptr);
         }
         else if (!strcmp((const char *) ptr->name,
+                         "authenticationMode"))
+        {
+            s->authenticationMode = mp::xml::get_text(ptr);
+        }
+        else if (!strcmp((const char *) ptr->name,
                          "cfAuth"))
         {
             s->cfAuth = mp::xml::get_text(ptr);
@@ -944,8 +1018,8 @@ bool yf::Zoom::Frontend::create_content_session(mp::Package &package,
                             "unable to open content config %s",
                             m_p->content_config_file.c_str());
                 *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
-                *addinfo = (char *)  odr_malloc(odr, 60 + tmp_file.length());
-                sprintf(*addinfo, "unable to open content config %s",
+                *addinfo = (char *)  odr_malloc(odr, 70 + tmp_file.length());
+                sprintf(*addinfo, "zoom: unable to open content config %s",
                         m_p->content_config_file.c_str());
                 return false;
             }
@@ -969,7 +1043,7 @@ bool yf::Zoom::Frontend::create_content_session(mp::Package &package,
             package.log("zoom", YLOG_WARN, "bad tmp_file %s", tmp_file.c_str());
             *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
             *addinfo = (char *)  odr_malloc(odr, 60 + tmp_file.length());
-            sprintf(*addinfo, "bad format of content tmp_file: %s",
+            sprintf(*addinfo, "zoom: bad format of content tmp_file: %s",
                     tmp_file.c_str());
             xfree(fname);
             return false;
@@ -987,8 +1061,8 @@ bool yf::Zoom::Frontend::create_content_session(mp::Package &package,
         {
             package.log("zoom", YLOG_WARN|YLOG_ERRNO, "create %s", fname);
             *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
-            *addinfo = (char *)  odr_malloc(odr, 40 + strlen(fname));
-            sprintf(*addinfo, "Could not create %s", fname);
+            *addinfo = (char *) odr_malloc(odr, 50 + strlen(fname));
+            sprintf(*addinfo, "zoom: could not create %s", fname);
             xfree(fname);
             return false;
         }
@@ -1136,7 +1210,7 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
             BackendPtr notfound;
             char *msg = (char*) odr_malloc(odr, strlen(name) + 30);
             *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
-            sprintf(msg, "Bad database argument: %s", name);
+            sprintf(msg, "zoom: bad database argument: %s", name);
             *addinfo = msg;
             return notfound;
         }
@@ -1246,8 +1320,8 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
         if (!xsp_doc)
         {
             *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
-            *addinfo = (char *) odr_malloc(odr, 40);
-            sprintf(*addinfo, "xmlParseMemory failed");
+            *addinfo = odr_strdup(odr, "zoom: xmlParseMemory failed "
+                                  "for literalTransform XSL");
             BackendPtr b;
             return b;
         }
@@ -1255,7 +1329,9 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
         if (!xsp)
         {
             *error = YAZ_BIB1_DATABASE_DOES_NOT_EXIST;
-            *addinfo = odr_strdup(odr, "xsltParseStylesheetDoc failed");
+            *addinfo =
+                odr_strdup(odr,"zoom: xsltParseStylesheetDoc failed "
+                           "for literalTransform XSL");
             BackendPtr b;
             xmlFreeDoc(xsp_doc);
             return b;
@@ -1281,7 +1357,7 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
             *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
             *addinfo = (char *)
                 odr_malloc(odr, 40 + sptr->transform_xsl_fname.length());
-            sprintf(*addinfo, "File could not be read: %s",
+            sprintf(*addinfo, "zoom: could not open file %s",
                     sptr->transform_xsl_fname.c_str());
             BackendPtr b;
             return b;
@@ -1290,16 +1366,19 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
         if (!xsp_doc)
         {
             *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
-            *addinfo = (char *) odr_malloc(odr, 40 + fname.length());
-            sprintf(*addinfo, "xmlParseFile failed. File: %s", fname.c_str());
+            *addinfo = (char *) odr_malloc(odr, 50 + fname.length());
+            sprintf(*addinfo, "zoom: xmlParseFile failed for file %s",
+                    fname.c_str());
             BackendPtr b;
             return b;
         }
         xsp = xsltParseStylesheetDoc(xsp_doc);
         if (!xsp)
         {
-            *error = YAZ_BIB1_DATABASE_DOES_NOT_EXIST;
-            *addinfo = odr_strdup(odr, "xsltParseStylesheetDoc failed");
+            *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
+            *addinfo = (char *) odr_malloc(odr, 50 + fname.length());
+            sprintf(*addinfo, "zoom: xsltParseStylesheetDoc failed "
+                    "for file %s", fname.c_str());
             BackendPtr b;
             xmlFreeDoc(xsp_doc);
             return b;
@@ -1321,7 +1400,7 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
     if (!cqlt)
     {
         *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
-        *addinfo = odr_strdup(odr, "Missing/invalid cql2rpn file");
+        *addinfo = odr_strdup(odr, "zoom: missing/invalid cql2rpn file");
         BackendPtr b;
         xsltFreeStylesheet(xsp);
         return b;
@@ -1340,8 +1419,7 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
     if (sptr->query_encoding.length())
         b->set_option("rpnCharset", sptr->query_encoding);
 
-    if (sptr->extraArgs.length())
-        b->set_option("extraArgs", sptr->extraArgs);
+    std::string extraArgs = sptr->extraArgs;
 
     b->set_option("timeout", m_p->zoom_timeout.c_str());
 
@@ -1394,6 +1472,9 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
             out_names[no_out_args] = "subdatabase";
             out_values[no_out_args++] = odr_strdup(odr, sptr->cfSubDB.c_str());
         }
+        if (!param_nocproxy && b->sptr->contentConnector.length())
+            param_nocproxy = "1";
+
         if (param_nocproxy)
         {
             out_names[no_out_args] = "nocproxy";
@@ -1402,32 +1483,69 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases(
     }
     else
     {
-        size_t found = authentication.find('/');
-
-        if (sptr->sru.length() && found != std::string::npos)
-        {
-            b->set_option("user", authentication.substr(0, found));
-            b->set_option("password", authentication.substr(found+1));
-        }
+        if (sptr->sru.length() == 0)
+            b->set_option("user", authentication); /* Z39.50 */
         else
-            b->set_option("user", authentication);
+        {
+            std::string user;
+            std::string password;
+            std::string authtype = sptr->authenticationMode;
 
+            {
+                const char *cstr = authentication.c_str();
+                const char *cp1 = strchr(cstr, '/');
+                if (cp1)
+                {
+                    password.assign(cp1 + 1);
+                    user.assign(cstr, cp1 - cstr);
+                }
+                else
+                    user.assign(cstr);
+            }
+
+            if (authtype.compare("url") == 0)
+            {
+                /* SRU URL encoding of auth stuff */
+                ODR o = odr_createmem(ODR_ENCODE);
+                char *path = 0;
+                const char *names[3];
+                const char *values[3];
+
+                names[0] = "x-username";
+                values[0] = user.c_str();
+                names[1] = "x-password";
+                values[1] = password.c_str();
+                names[2] = 0;
+                values[2] = 0;
+
+                yaz_array_to_uri(&path, o, (char **) names, (char **) values);
+                if (extraArgs.length())
+                    extraArgs.append("&");
+                extraArgs.append(path);
+                odr_destroy(o);
+            }
+            else
+            {
+                b->set_option("user", user);
+                if (password.length())
+                    b->set_option("password", password);
+            }
+        }
         if (proxy.length())
             b->set_option("proxy", proxy);
     }
-    std::string url;
+    if (extraArgs.length())
+        b->set_option("extraArgs", extraArgs);
+
+    std::string url(sptr->target);
     if (sptr->sru.length())
     {
-        url = "http://" + sptr->target;
         b->set_option("sru", sptr->sru);
-
+        if (url.find("://") == std::string::npos)
+            url = "http://" + url;
         if (sptr->sru_version.length())
             b->set_option("sru_version", sptr->sru_version);
     }
-    else
-    {
-        url = sptr->target;
-    }
     if (no_out_args)
     {
         char *x_args = 0;
@@ -2264,6 +2382,14 @@ next_proxy:
     ZOOM_query q = ZOOM_query_create();
     ZOOM_query_sortby2(q, b->sptr->sortStrategy.c_str(), sortkeys.c_str());
 
+    Z_FacetList *fl = 0;
+
+    // Facets for request.. And later for reponse
+    if (!fl)
+        fl = yaz_oi_get_facetlist(&sr->otherInfo);
+    if (!fl)
+        fl = yaz_oi_get_facetlist(&sr->additionalSearchInfo);
+
     if (b->get_option("sru"))
     {
         int status = 0;
@@ -2287,14 +2413,14 @@ next_proxy:
         {
             ZOOM_query_cql(q, wrbuf_cstr(wrb));
             package.log("zoom", YLOG_LOG, "CQL: %s", wrbuf_cstr(wrb));
-            b->search(q, &hits, &error, &addinfo, odr);
+            b->search(q, &hits, &error, &addinfo, &fl, odr);
         }
         ZOOM_query_destroy(q);
 
         if (status)
         {
             error = YAZ_BIB1_MALFORMED_QUERY;
-            const char *addinfo = "can not convert from RPN to CQL/SOLR";
+            const char *addinfo = "can not convert from RPN to CQL/Solr";
             log_diagnostic(package, error, addinfo);
             apdu_res = odr.create_searchResponse(apdu_req, error, addinfo);
             package.response() = apdu_res;
@@ -2305,7 +2431,7 @@ next_proxy:
     {
         ZOOM_query_prefix(q, wrbuf_cstr(pqf_wrbuf));
         package.log("zoom", YLOG_LOG, "search PQF: %s", wrbuf_cstr(pqf_wrbuf));
-        b->search(q, &hits, &error, &addinfo, odr);
+        b->search(q, &hits, &error, &addinfo, &fl, odr);
         ZOOM_query_destroy(q);
     }
 
@@ -2337,6 +2463,9 @@ next_proxy:
             odr_intdup(odr, number_of_records_returned);
     }
     apdu_res->u.searchResponse->resultCount = odr_intdup(odr, hits);
+    if (fl)
+        yaz_oi_set_facetlist(&apdu_res->u.searchResponse->additionalSearchInfo,
+                             odr, fl);
     package.response() = apdu_res;
 }
 
@@ -2534,8 +2663,8 @@ void yf::Zoom::Frontend::auth(mp::Package &package, Z_InitRequest *req,
     {
         // something fundamental broken in lookup.
         *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR;
-        *addinfo = odr_strdup(odr, "Torus server unavailable or "
-                              "incorrectly configured");
+        *addinfo = odr_strdup(odr, "zoom: torus server unavailable or "
+                              "incorrectly configured.");
         return;
     }
     const xmlNode *ptr = xmlDocGetRootElement(doc);