Added include stdlib.h.
[yazproxy-moved-to-github.git] / src / yaz-proxy.cpp
index fa3b441..1c655b5 100644 (file)
@@ -1,5 +1,5 @@
-/* $Id: yaz-proxy.cpp,v 1.12 2004-11-30 21:10:45 adam Exp $
-   Copyright (c) 1998-2004, Index Data.
+/* $Id: yaz-proxy.cpp,v 1.17 2005-01-11 20:58:04 adam Exp $
+   Copyright (c) 1998-2005, Index Data.
 
 This file is part of the yaz-proxy.
 
@@ -19,36 +19,32 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 02111-1307, USA.
  */
 
-#ifdef WIN32
-#else
+#if HAVE_UNISTD_H
 #include <unistd.h>
 #endif
-
-#if HAVE_GETTIMEOFDAY
+#if HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
 
 #include <assert.h>
 #include <time.h>
-#include <sys/types.h>
 #include <fcntl.h>
 
 #include <yaz/srw.h>
 #include <yaz/marcdisp.h>
 #include <yaz/yaz-iconv.h>
-#include <yaz/ylog.h>
+#include <yaz/log.h>
 #include <yaz/diagbib1.h>
-#include <yazproxy/proxy.h>
+#include "proxyp.h"
 #include <yaz/pquery.h>
 #include <yaz/otherinfo.h>
 
-#if HAVE_XSLT
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-#include <libxslt/xsltutils.h>
-#include <libxslt/transform.h>
-#endif
-
 static const char *apdu_name(Z_APDU *apdu)
 {
     switch (apdu->which)
@@ -170,6 +166,9 @@ Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable,
 #else
     m_time_tv = 0;
 #endif
+    m_usemarcon_ini_stage1 = 0;
+    m_usemarcon_ini_stage2 = 0;
+    m_usemarcon = new Yaz_usemarcon();
     if (!m_parent)
        low_socket_open();
 }
@@ -196,6 +195,9 @@ Yaz_Proxy::~Yaz_Proxy()
     xfree (m_schema);
     xfree (m_backend_type);
     xfree (m_backend_charset);
+    xfree (m_usemarcon_ini_stage1);
+    xfree (m_usemarcon_ini_stage2);
+    delete m_usemarcon;
     if (m_s2z_odr_init)
        odr_destroy(m_s2z_odr_init);
     if (m_s2z_odr_search)
@@ -689,8 +691,8 @@ int Yaz_Proxy::convert_xsl(Z_NamePlusRecordList *p, Z_APDU *apdu)
 
 void Yaz_Proxy::convert_xsl_delay()
 {
-    Z_NamePlusRecord *npr = m_stylesheet_nprl->records[m_stylesheet_offset];
 #if HAVE_XSLT
+    Z_NamePlusRecord *npr = m_stylesheet_nprl->records[m_stylesheet_offset];
     if (npr->which == Z_NamePlusRecord_databaseRecord)
     {
        Z_External *r = npr->u.databaseRecord;
@@ -756,6 +758,54 @@ void Yaz_Proxy::convert_to_frontend_type(Z_NamePlusRecordList *p)
                Z_External *r = npr->u.databaseRecord;
                if (r->which == Z_External_octet)
                {
+#if HAVE_USEMARCON
+                   if (m_usemarcon_ini_stage1 && *m_usemarcon_ini_stage1)
+                   {
+                       if (!m_usemarcon->m_stage1)
+                       {
+                           m_usemarcon->m_stage1 = new CDetails();
+                       }
+                       m_usemarcon->m_stage1->SetIniFileName(m_usemarcon_ini_stage1);
+                       m_usemarcon->m_stage1->SetMarcRecord((char*) r->u.octet_aligned->buf, r->u.octet_aligned->len);
+                       int res = m_usemarcon->m_stage1->Start();
+                       if (res == 0)
+                       {
+                           char *converted;
+                           int convlen;
+                           m_usemarcon->m_stage1->GetMarcRecord(converted, convlen);
+                           if (m_usemarcon_ini_stage2 && *m_usemarcon_ini_stage2)
+                           {
+                               if (!m_usemarcon->m_stage2)
+                               {
+                                   m_usemarcon->m_stage2 = new CDetails();
+                               }
+                               m_usemarcon->m_stage2->SetIniFileName(m_usemarcon_ini_stage2);
+                               m_usemarcon->m_stage2->SetMarcRecord(converted, convlen);
+                               res = m_usemarcon->m_stage2->Start();
+                               if (res == 0)
+                               {
+                                   free(converted);
+                                   m_usemarcon->m_stage2->GetMarcRecord(converted, convlen);
+                               }
+                               else
+                               {
+                                   yaz_log(YLOG_LOG, "%sUSEMARCON stage 2 error %d", m_session_str, res);
+                               }
+                           }
+                           npr->u.databaseRecord =
+                               z_ext_record(odr_encode(),
+                                            m_frontend_type,
+                                            converted,
+                                            strlen(converted));
+                           free(converted);
+                       }
+                       else
+                       {
+                           yaz_log(YLOG_LOG, "%sUSEMARCON stage 1 error %d", m_session_str, res);
+                       }
+                       continue;
+                   }
+#endif
                    npr->u.databaseRecord =
                        z_ext_record(odr_encode(),
                                     m_frontend_type,
@@ -1107,7 +1157,11 @@ int Yaz_Proxy::send_to_client(Z_APDU *apdu)
        {
            if (p && p->which == Z_Records_DBOSD)
            {
-               if (m_backend_type)
+               if (m_backend_type
+#if HAVE_USEMARCON
+                   || m_usemarcon_ini_stage1 || m_usemarcon_ini_stage2
+#endif
+                   )
                    convert_to_frontend_type(p->u.databaseOrSurDiagnostics);
                if (m_marcxml_flag)
                    convert_to_marcxml(p->u.databaseOrSurDiagnostics,
@@ -1148,7 +1202,11 @@ int Yaz_Proxy::send_to_client(Z_APDU *apdu)
        }
        if (p && p->which == Z_Records_DBOSD)
        {
-           if (m_backend_type)
+           if (m_backend_type 
+#if HAVE_USEMARCON
+               || m_usemarcon_ini_stage1 || m_usemarcon_ini_stage2
+#endif
+               )
                convert_to_frontend_type(p->u.databaseOrSurDiagnostics);
            if (m_marcxml_flag)
                convert_to_marcxml(p->u.databaseOrSurDiagnostics,
@@ -1505,6 +1563,7 @@ void Yaz_Proxy::recv_GDU(Z_GDU *apdu, int len)
            reduce = (reduce > nreduce) ? reduce : nreduce;
        }
     }
+    m_http_version = 0;
     if (reduce)  
     {
        yaz_log(YLOG_LOG, "%sdelay=%d bw=%d pdu=%d limit-bw=%d limit-pdu=%d",
@@ -1664,7 +1723,9 @@ Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
                                    m_default_target,
                                    sr->preferredRecordSyntax, rc,
                                    &addinfo, &stylesheet_name, &m_schema,
-                                   &m_backend_type, &m_backend_charset);
+                                   &m_backend_type, &m_backend_charset,
+                                    &m_usemarcon_ini_stage1,
+                                   &m_usemarcon_ini_stage2);
        if (stylesheet_name)
        {
            m_parent->low_socket_close();
@@ -1738,7 +1799,10 @@ Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
                                    pr->preferredRecordSyntax,
                                    pr->recordComposition,
                                    &addinfo, &stylesheet_name, &m_schema,
-                                   &m_backend_type, &m_backend_charset);
+                                   &m_backend_type, &m_backend_charset,
+                                    &m_usemarcon_ini_stage1,
+                                   &m_usemarcon_ini_stage2
+                                   );
        if (stylesheet_name)
        {
            m_parent->low_socket_close();
@@ -1822,6 +1886,70 @@ void Yaz_Proxy::srw_get_client(const char *db, const char **backend_db)
        m_default_target = xstrdup(t);
     }
 }
+
+int Yaz_Proxy::file_access(Z_HTTP_Request *hreq)
+{
+    yaz_log(YLOG_LOG, "file_access");
+    if (strcmp(hreq->method, "GET"))
+       return 0;
+    struct stat sbuf;
+    if (hreq->path[0] != '/')
+    {
+       yaz_log(YLOG_WARN, "Path != /");
+       return 0;
+    }
+    const char *cp = hreq->path;
+    while (*cp)
+    {
+       if (*cp == '/' && strchr("/.", cp[1]))
+           return 0;
+       cp++;
+    }
+    const char *fname = hreq->path+1;
+    if (stat(fname, &sbuf))
+    {
+       yaz_log(YLOG_WARN, "stat %s failed", fname);
+       return 0;
+    }
+    if ((sbuf.st_mode & S_IFMT) != S_IFREG)
+       return 0;
+    if (sbuf.st_size > (off_t) 1000000)
+       return 0;
+
+    ODR o = odr_encode();
+    Yaz_ProxyConfig *cfg = check_reconfigure();
+    const char *ctype = cfg->check_mime_type(fname);
+    Z_GDU *gdu = z_get_HTTP_Response(o, 200);
+    Z_HTTP_Response *hres = gdu->u.HTTP_Response;
+    if (m_http_version)
+       hres->version = odr_strdup(o, m_http_version);
+    z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
+    if (m_http_keepalive)
+        z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
+    else
+       timeout(0);
+
+    hres->content_len = sbuf.st_size;
+    hres->content_buf = (char*) odr_malloc(o, hres->content_len);
+    FILE *f = fopen(fname, "rb");
+    if (f)
+    {
+       fread(hres->content_buf, 1, hres->content_len, f);
+       fclose(f);
+    }
+    else
+    {
+       return 0;
+    }
+    if (m_log_mask & PROXY_LOG_REQ_CLIENT)
+    {
+       yaz_log (YLOG_LOG, "%sSending file %s to client", m_session_str,
+                fname);
+    }
+    int len;
+    send_GDU(gdu, &len);
+    return 1;
+}
        
 void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
 {
@@ -1862,10 +1990,15 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
     char *charset = 0;
     Z_SRW_diagnostic *diagnostic = 0;
     int num_diagnostic = 0;
-    if (yaz_srw_decode(hreq, &srw_pdu, &soap_package, odr_decode(),
-                      &charset) == 0
-       || yaz_sru_decode(hreq, &srw_pdu, &soap_package, odr_decode(),
-                         &charset, &diagnostic, &num_diagnostic) == 0)
+
+    if (file_access(hreq))
+    {
+       return;
+    }
+    else if (yaz_srw_decode(hreq, &srw_pdu, &soap_package, odr_decode(),
+                           &charset) == 0
+            || yaz_sru_decode(hreq, &srw_pdu, &soap_package, odr_decode(),
+                              &charset, &diagnostic, &num_diagnostic) == 0)
     {
        m_s2z_odr_init = odr_createmem(ODR_ENCODE);
        m_s2z_odr_search = odr_createmem(ODR_ENCODE);
@@ -2121,10 +2254,7 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
            send_to_srw_client_error(4, 0);
         }
     }
-    int len = 0;
-    Z_GDU *p = z_get_HTTP_Response(odr_encode(), 400);
-    timeout(0);
-    send_GDU(p, &len);
+    send_http_response(400);
 }
 
 void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu)
@@ -2156,8 +2286,16 @@ void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu)
     m_client = get_client(apdu, get_cookie(oi), get_proxy(oi));
     if (!m_client)
     {
-       delete this;
-       return;
+       if (m_http_version)
+       {
+           send_http_response(404);
+           return;
+       }
+       else
+       {
+           delete this;
+           return;
+       }
     }
     m_client->m_server = this;
 
@@ -2256,7 +2394,7 @@ void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu)
 
     // delete other info construct completely if 0 elements
     get_otherInfoAPDU(apdu, &oi);
-    if (*oi && (*oi)->num_elements == 0)
+    if (oi && *oi && (*oi)->num_elements == 0)
         *oi = 0;
 
     if (apdu->which == Z_APDU_presentRequest &&