Added support for character set conversion of query terms. The XML
[yazproxy-moved-to-github.git] / src / yaz-proxy.cpp
index 4400bbb..f174362 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: yaz-proxy.cpp,v 1.22 2005-02-11 15:19:08 adam Exp $
+/* $Id: yaz-proxy.cpp,v 1.25 2005-05-04 08:31:44 adam Exp $
    Copyright (c) 1998-2005, Index Data.
 
 This file is part of the yaz-proxy.
@@ -38,6 +38,7 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #endif
 
 #include <assert.h>
+#include <stdlib.h>
 #include <time.h>
 #include <fcntl.h>
 
@@ -116,9 +117,9 @@ Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable,
     m_keepalive_limit_pdu = 1000;
     m_proxyTarget = 0;
     m_default_target = 0;
-    m_proxy_authentication = 0;
     m_proxy_negotiation_charset = 0;
     m_proxy_negotiation_lang = 0;
+    m_charset_converter = new Yaz_CharsetConverter;
     m_max_clients = 150;
     m_log_mask = 0;
     m_seed = time(0);
@@ -140,7 +141,7 @@ Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable,
     m_referenceId = 0;
     m_referenceId_mem = nmem_create();
     m_config = 0;
-    m_marcxml_flag = 0;
+    m_marcxml_mode = none;
     m_stylesheet_xsp = 0;
     m_stylesheet_nprl = 0;
     m_s2z_stylesheet = 0;
@@ -196,9 +197,9 @@ Yaz_Proxy::~Yaz_Proxy()
 
     xfree(m_proxyTarget);
     xfree(m_default_target);
-    xfree(m_proxy_authentication);
     xfree(m_proxy_negotiation_charset);
     xfree(m_proxy_negotiation_lang);
+    delete m_charset_converter;
     xfree(m_optimize);
 
 #if HAVE_XSLT
@@ -222,6 +223,11 @@ Yaz_Proxy::~Yaz_Proxy()
     delete m_config;
 }
 
+void Yaz_Proxy::set_debug_mode(int mode)
+{
+    m_debug_mode = mode;
+}
+
 int Yaz_Proxy::set_config(const char *config)
 {
     delete m_config;
@@ -242,14 +248,6 @@ void Yaz_Proxy::set_default_target(const char *target)
        m_default_target = (char *) xstrdup (target);
 }
 
-void Yaz_Proxy::set_proxy_authentication (const char *auth)
-{
-    xfree (m_proxy_authentication);
-    m_proxy_authentication = 0;
-    if (auth)
-       m_proxy_authentication = (char *) xstrdup (auth);
-}
-
 void Yaz_Proxy::set_proxy_negotiation (const char *charset, const char *lang)
 {
     yaz_log(YLOG_LOG, "%sSet the proxy negotiation: charset to '%s', "
@@ -310,13 +308,12 @@ IYaz_PDU_Observer *Yaz_Proxy::sessionNotify(IYaz_PDU_Observable
        new_proxy->set_APDU_yazlog(1);
     else
        new_proxy->set_APDU_yazlog(0);
-    new_proxy->set_proxy_authentication(m_proxy_authentication);
-    new_proxy->set_proxy_negotiation(m_proxy_negotiation_charset,
-       m_proxy_negotiation_lang);
     sprintf(new_proxy->m_session_str, "%ld:%d ", (long) time(0), m_session_no);
     m_session_no++;
     yaz_log (YLOG_LOG, "%sNew session %s", new_proxy->m_session_str,
             the_PDU_Observable->getpeername());
+    new_proxy->set_proxy_negotiation(m_proxy_negotiation_charset,
+       m_proxy_negotiation_lang);
     return new_proxy;
 }
 
@@ -415,20 +412,21 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
        Yaz_ProxyConfig *cfg = check_reconfigure();
        if (proxy_host)
        {
-#if 0
-/* only to be enabled for debugging... */
-           if (!strcmp(proxy_host, "stop"))
-               exit(0);
-#endif
+           if (parent && parent->m_debug_mode)
+           {
+                // only to be enabled for debugging...
+               if (!strcmp(proxy_host, "stop"))
+                   exit(0);
+           }
            xfree(m_default_target);
            m_default_target = xstrdup(proxy_host);
        }
        proxy_host = m_default_target;
        int client_idletime = -1;
        const char *cql2rpn_fname = 0;
-       const char *authentication = 0;
        const char *negotiation_charset = 0;
        const char *negotiation_lang = 0;
+       const char *query_charset = 0;
        url[0] = m_default_target;
        url[1] = 0;
        if (cfg)
@@ -442,9 +440,9 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
                                 &m_keepalive_limit_pdu,
                                 &pre_init,
                                 &cql2rpn_fname,
-                                &authentication,
                                 &negotiation_charset,
-                                &negotiation_lang);
+                                &negotiation_lang,
+                                &query_charset);
        }
        if (client_idletime != -1)
        {
@@ -453,11 +451,13 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
        }
        if (cql2rpn_fname)
            m_cql2rpn.set_pqf_file(cql2rpn_fname);
-       if (authentication)
-           set_proxy_authentication(authentication);
        if (negotiation_charset || negotiation_lang)
+       {
+           yaz_log(YLOG_LOG, "set_proxy_negotiation...");
            set_proxy_negotiation(negotiation_charset,
                negotiation_lang);
+       }
+       m_charset_converter->set_target_query_charset(query_charset);
        if (!url[0])
        {
            yaz_log(YLOG_LOG, "%sNo default target", m_session_str);
@@ -561,23 +561,9 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
        }
         Z_InitRequest *initRequest = apdu->u.initRequest;
 
-        if (!initRequest->idAuthentication)
-        {
-            if (m_proxy_authentication)
-            {
-                initRequest->idAuthentication =
-                    (Z_IdAuthentication *)
-                    odr_malloc (odr_encode(),
-                                sizeof(*initRequest->idAuthentication));
-                initRequest->idAuthentication->which =
-                    Z_IdAuthentication_open;
-                initRequest->idAuthentication->u.open =
-                    odr_strdup (odr_encode(), m_proxy_authentication);
-            }
-        }
-       else
+        if (initRequest->idAuthentication)
        {
-           // the client use authentication. We set the keepalive PDU
+           // the client uses authentication. We set the keepalive PDU
            // to 0 so we don't cache it in releaseClient
            m_keepalive_limit_pdu = 0;
        }
@@ -844,6 +830,7 @@ void Yaz_Proxy::convert_to_frontend_type(Z_NamePlusRecordList *p)
                        continue;
                    }
 #endif
+/* HAVE_USEMARCON */
                    npr->u.databaseRecord =
                        z_ext_record(odr_encode(),
                                     m_frontend_type,
@@ -871,7 +858,18 @@ void Yaz_Proxy::convert_to_marcxml(Z_NamePlusRecordList *p,
        if (npr->which == Z_NamePlusRecord_databaseRecord)
        {
            Z_External *r = npr->u.databaseRecord;
-           if (r->which == Z_External_octet)
+           if (r->which == Z_External_OPAC)
+           {
+               WRBUF w = wrbuf_alloc();
+
+               yaz_display_OPAC(w, r->u.opac, 0);
+               npr->u.databaseRecord = z_ext_record(
+                   odr_encode(), VAL_TEXT_XML,
+                   wrbuf_buf(w), wrbuf_len(w)
+                   );
+               wrbuf_free(w, 1);
+           }
+           else if (r->which == Z_External_octet)
            {
                int rlen;
                char *result;
@@ -879,9 +877,8 @@ void Yaz_Proxy::convert_to_marcxml(Z_NamePlusRecordList *p,
                                        r->u.octet_aligned->len,
                                        &result, &rlen))
                {
-                   npr->u.databaseRecord = z_ext_record(odr_encode(),
-                                                        VAL_TEXT_XML,
-                                                        result, rlen);
+                   npr->u.databaseRecord =
+                       z_ext_record(odr_encode(), VAL_TEXT_XML, result, rlen);
                }
            }
        }
@@ -1200,7 +1197,7 @@ int Yaz_Proxy::send_to_client(Z_APDU *apdu)
 #endif
                    )
                    convert_to_frontend_type(p->u.databaseOrSurDiagnostics);
-               if (m_marcxml_flag)
+               if (m_marcxml_mode == marcxml)
                    convert_to_marcxml(p->u.databaseOrSurDiagnostics,
                                       m_backend_charset);
                if (convert_xsl(p->u.databaseOrSurDiagnostics, apdu))
@@ -1245,7 +1242,7 @@ int Yaz_Proxy::send_to_client(Z_APDU *apdu)
 #endif
                )
                convert_to_frontend_type(p->u.databaseOrSurDiagnostics);
-           if (m_marcxml_flag)
+           if (m_marcxml_mode == marcxml)
                convert_to_marcxml(p->u.databaseOrSurDiagnostics,
                                   m_backend_charset);
            if (convert_xsl(p->u.databaseOrSurDiagnostics, apdu))
@@ -1808,6 +1805,24 @@ Z_APDU *Yaz_Proxy::handle_query_transformation(Z_APDU *apdu)
     return apdu;
 }
 
+Z_APDU *Yaz_Proxy::handle_query_charset_conversion(Z_APDU *apdu)
+{
+    if (apdu->which == Z_APDU_searchRequest &&
+       apdu->u.searchRequest->query)
+    {
+       if (apdu->u.searchRequest->query->which == Z_Query_type_1
+           || apdu->u.searchRequest->query->which == Z_Query_type_101)
+       {
+           if (m_http_version)
+               m_charset_converter->set_client_query_charset("UTF-8");
+           Z_RPNQuery *rpnquery = apdu->u.searchRequest->query->u.type_1;
+           m_charset_converter->convert_type_1(rpnquery, odr_encode());
+       }
+    }
+    return apdu;
+}
+
+
 Z_APDU *Yaz_Proxy::handle_query_validation(Z_APDU *apdu)
 {
     if (apdu->which == Z_APDU_searchRequest)
@@ -1850,11 +1865,11 @@ int Yaz_Proxy::handle_authentication(Z_APDU *apdu)
     int ret;
     if (req->idAuthentication == 0)
     {
-       ret = cfg->check_authentication(0, 0, 0);
+       ret = cfg->client_authentication(m_default_target, 0, 0, 0);
     }
     else if (req->idAuthentication->which == Z_IdAuthentication_idPass)
     {
-       ret = cfg->check_authentication(
+       ret = cfg->client_authentication(m_default_target,
            req->idAuthentication->u.idPass->userId,
            req->idAuthentication->u.idPass->groupId,
            req->idAuthentication->u.idPass->password);
@@ -1865,16 +1880,19 @@ int Yaz_Proxy::handle_authentication(Z_APDU *apdu)
        *user = '\0';
        *pass = '\0';
        sscanf(req->idAuthentication->u.open, "%63[^/]/%63s", user, pass);
-       ret = cfg->check_authentication(user, 0, pass);
+       ret = cfg->client_authentication(m_default_target, user, 0, pass);
     }
     else
-       ret = cfg->check_authentication(0, 0, 0);
+       ret = cfg->client_authentication(m_default_target, 0, 0, 0);
+
+    cfg->target_authentication(m_default_target, odr_encode(), req);
+
     return ret;
 }
 
 Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
 {
-    m_marcxml_flag = 0;
+    m_marcxml_mode = none;
     if (apdu->which == Z_APDU_searchRequest)
     {
        Z_SearchRequest *sr = apdu->u.searchRequest;
@@ -1927,6 +1945,7 @@ Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
        {
            sr->smallSetElementSetNames = 0;
            sr->mediumSetElementSetNames = 0;
+           m_marcxml_mode = marcxml;
            if (m_backend_type)
            {
                
@@ -1938,7 +1957,6 @@ Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
                sr->preferredRecordSyntax =
                    yaz_oidval_to_z3950oid(odr_encode(), CLASS_RECSYN,
                                           VAL_USMARC);
-           m_marcxml_flag = 1;
        }
        else if (err)
        {
@@ -2003,6 +2021,7 @@ Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
        if (err == -1)
        {
            pr->recordComposition = 0;
+           m_marcxml_mode = marcxml;
            if (m_backend_type)
            {
                
@@ -2014,7 +2033,6 @@ Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
                pr->preferredRecordSyntax =
                    yaz_oidval_to_z3950oid(odr_encode(), CLASS_RECSYN,
                                           VAL_USMARC);
-           m_marcxml_flag = 1;
        }
        else if (err)
        {
@@ -2072,7 +2090,6 @@ void Yaz_Proxy::srw_get_client(const char *db, const char **backend_db)
 int Yaz_Proxy::file_access(Z_HTTP_Request *hreq)
 {
     struct stat sbuf;
-    yaz_log(YLOG_LOG, "file_access");
     if (strcmp(hreq->method, "GET"))
        return 0;
     if (hreq->path[0] != '/')
@@ -2619,10 +2636,14 @@ void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu)
        apdu = handle_query_transformation(apdu);
 
     if (apdu)
+       apdu = handle_query_charset_conversion(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 
@@ -2837,7 +2858,8 @@ void Yaz_Proxy::pre_init()
                                          &cql2rpn,
                                          &authentication,
                                          &negotiation_charset,
-                                         &negotiation_lang) ; i++)
+                                         &negotiation_lang,
+                                         0) ; i++)
     {
        if (pre_init)
        {