Picky SRU decode. Fix leak for XSL code. Throw better diagnostics
[yazpp-moved-to-github.git] / src / yaz-proxy.cpp
index abab60b..00daeef 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 1998-2004, Index Data.
  * See the file LICENSE for details.
  * 
- * $Id: yaz-proxy.cpp,v 1.80 2004-01-07 20:56:03 adam Exp $
+ * $Id: yaz-proxy.cpp,v 1.86 2004-01-09 18:11:15 adam Exp $
  */
 
 #include <assert.h>
@@ -107,6 +107,7 @@ Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable,
     m_config = 0;
     m_marcxml_flag = 0;
     m_stylesheet_schema = 0;
+    m_s2z_stylesheet = 0;
     m_schema = 0;
     m_initRequest_apdu = 0;
     m_initRequest_mem = 0;
@@ -610,6 +611,7 @@ void Yaz_Proxy::convert_xsl(Z_NamePlusRecordList *p)
                p->records[i]->u.databaseRecord = 
                    z_ext_record(odr_encode(), VAL_TEXT_XML,
                                 (char*) out_buf, out_len);
+               xmlFree(out_buf);
                xmlFreeDoc(doc);
                xmlFreeDoc(res);
            }
@@ -742,9 +744,9 @@ int Yaz_Proxy::send_srw_response(Z_SRW_PDU *srw_pdu)
     soap_package->u.generic->ns = soap_handlers[0].ns;
     soap_package->u.generic->p = (void *) srw_pdu;
     soap_package->ns = m_soap_ns;
-    z_soap_codec_enc(o, &soap_package,
-                    &hres->content_buf, &hres->content_len,
-                    soap_handlers, 0, 0);
+    z_soap_codec_enc_xsl(o, &soap_package,
+                        &hres->content_buf, &hres->content_len,
+                        soap_handlers, 0, m_s2z_stylesheet);
     if (m_log_mask & PROXY_LOG_REQ_CLIENT)
     {
        yaz_log (LOG_LOG, "%sSending %s to client", m_session_str,
@@ -756,7 +758,7 @@ int Yaz_Proxy::send_srw_response(Z_SRW_PDU *srw_pdu)
     return r;
 }
 
-int Yaz_Proxy::send_to_srw_client_error(int srw_error)
+int Yaz_Proxy::send_to_srw_client_error(int srw_error, const char *add)
 {
     ODR o = odr_encode();
     Z_SRW_PDU *srw_pdu = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
@@ -766,7 +768,7 @@ int Yaz_Proxy::send_to_srw_client_error(int srw_error)
     srw_res->diagnostics = (Z_SRW_diagnostic *)
        odr_malloc(o, sizeof(*srw_res->diagnostics));
     srw_res->diagnostics[0].code =  odr_intdup(o, srw_error);
-    srw_res->diagnostics[0].details = 0;
+    srw_res->diagnostics[0].details = add ? odr_strdup(o, add) : 0;
     return send_srw_response(srw_pdu);
 }
 
@@ -844,7 +846,8 @@ int Yaz_Proxy::send_to_srw_client_ok(int hits, Z_Records *records, int start)
     
 }
 
-int Yaz_Proxy::send_srw_explain()
+int Yaz_Proxy::send_srw_explain_response(Z_SRW_diagnostic *diagnostics,
+                                       int num_diagnostics)
 {
     Z_SRW_PDU *res = yaz_srw_get(odr_encode(), Z_SRW_explain_response);
     Z_SRW_explainResponse *er = res->u.explain_response;
@@ -853,7 +856,6 @@ int Yaz_Proxy::send_srw_explain()
     if (cfg)
     {
        int len;
-       assert (m_proxyTarget);
        char *b = cfg->get_explain(odr_encode(), 0 /* target */,
                                   0 /* db */, &len);
        if (b)
@@ -863,6 +865,8 @@ int Yaz_Proxy::send_srw_explain()
            er->record.recordPacking = m_s2z_packing;
        }
     }
+    er->diagnostics = diagnostics;
+    er->num_diagnostics = num_diagnostics;
     return send_srw_response(res);
 }
 
@@ -875,11 +879,11 @@ int Yaz_Proxy::send_PDU_convert(Z_APDU *apdu, int *len)
            Z_InitResponse *res = apdu->u.initResponse;
            if (*res->result == 0)
            {
-               send_to_srw_client_error(3);
+               send_to_srw_client_error(3, 0);
            }
            else if (!m_s2z_search_apdu)
            {
-               send_srw_explain();
+               send_srw_explain_response(0, 0);
            }
            else
            {
@@ -897,6 +901,16 @@ int Yaz_Proxy::send_PDU_convert(Z_APDU *apdu, int *len)
            }
            else if (m_s2z_present_apdu)
            {
+               // adjust 
+               Z_PresentRequest *pr = m_s2z_present_apdu->u.presentRequest;
+               
+               if (*pr->resultSetStartPoint <= m_s2z_hit_count)
+               {
+                   if (*pr->numberOfRecordsRequested+ *pr->resultSetStartPoint
+                       > m_s2z_hit_count)
+                       *pr->numberOfRecordsRequested =
+                           1 + m_s2z_hit_count - *pr->resultSetStartPoint;
+               }
                handle_incoming_Z_PDU(m_s2z_present_apdu);
            }
            else
@@ -1554,10 +1568,12 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
     Z_SRW_PDU *srw_pdu = 0;
     Z_SOAP *soap_package = 0;
     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) == 0)
+                         &charset, &diagnostic, &num_diagnostic) == 0)
     {
        m_s2z_odr_init = odr_createmem(ODR_ENCODE);
        m_s2z_odr_search = odr_createmem(ODR_ENCODE);
@@ -1565,10 +1581,39 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
        m_s2z_init_apdu = 0;
        m_s2z_search_apdu = 0;
        m_s2z_present_apdu = 0;
+
+       m_s2z_stylesheet = 0;
+       
        if (srw_pdu->which == Z_SRW_searchRetrieve_request)
        {
            Z_SRW_searchRetrieveRequest *srw_req = srw_pdu->u.request;
 
+           // recordXPath unsupported.
+           if (srw_req->recordXPath)
+            {
+               yaz_add_srw_diagnostic(odr_decode(),
+                                      &diagnostic, &num_diagnostic,
+                                      72, 0);
+            }
+           // must have a query
+           if (!srw_req->query.cql)
+           {
+               yaz_add_srw_diagnostic(odr_decode(),
+                                      &diagnostic, &num_diagnostic,
+                                      7, "query");
+           }
+           // sort unsupported
+           if (srw_req->sort_type != Z_SRW_sort_type_none)
+           {
+               yaz_add_srw_diagnostic(odr_decode(),
+                                      &diagnostic, &num_diagnostic,
+                                      80, 0);
+           }
+           // save stylesheet
+           if (srw_req->stylesheet)
+               m_s2z_stylesheet =
+                   odr_strdup(m_s2z_odr_init, srw_req->stylesheet);
+                                             
            // set packing for response records ..
            if (srw_req->recordPacking &&
                !strcmp(srw_req->recordPacking, "xml"))
@@ -1576,6 +1621,19 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
            else
                m_s2z_packing = Z_SRW_recordPacking_string;
 
+           if (num_diagnostic)
+           {
+               Z_SRW_PDU *srw_pdu =
+                   yaz_srw_get(odr_encode(),
+                               Z_SRW_searchRetrieve_response);
+               Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response;
+               
+               srw_res->diagnostics = diagnostic;
+               srw_res->num_diagnostics = num_diagnostic;
+               send_srw_response(srw_pdu);
+               return;
+           }
+
            // prepare search PDU
            m_s2z_search_apdu = zget_APDU(m_s2z_odr_search,
                                          Z_APDU_searchRequest);
@@ -1624,7 +1682,7 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
                    yaz_log(LOG_LOG, "%*s^\n", off+4, "");
                    yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
                    
-                   send_to_srw_client_error(10);
+                   send_to_srw_client_error(10, 0);
                    return;
                }
                query->which = Z_Query_type_1;
@@ -1634,7 +1692,7 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
            }
            else
            {
-               send_to_srw_client_error(11);
+               send_to_srw_client_error(7, "query");
                return;
            }
 
@@ -1712,16 +1770,26 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
        else if (srw_pdu->which == Z_SRW_explain_request)
        {
            Z_SRW_explainRequest *srw_req = srw_pdu->u.explain_request;
-           
+
+           // save stylesheet
+           if (srw_req->stylesheet)
+               m_s2z_stylesheet =
+                   odr_strdup(m_s2z_odr_init, srw_req->stylesheet);
+
            if (srw_req->recordPacking &&
                !strcmp(srw_req->recordPacking, "xml"))
                m_s2z_packing = Z_SRW_recordPacking_XML;
            else
                m_s2z_packing = Z_SRW_recordPacking_string;
 
+           if (num_diagnostic)
+           {
+               send_srw_explain_response(diagnostic, num_diagnostic);
+               return;
+           }
+
            if (!m_client)
            {
-               yaz_log(LOG_LOG, "handle_incoming: initRequest");
                m_s2z_init_apdu = zget_APDU(m_s2z_odr_init,
                                            Z_APDU_initRequest);
                
@@ -1731,9 +1799,28 @@ void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
                handle_incoming_Z_PDU(m_s2z_init_apdu);
            }
            else
-               send_srw_explain();
+               send_srw_explain_response(0, 0);
            return;
        }
+       else if (srw_pdu->which == Z_SRW_scan_request)
+        {
+           yaz_add_srw_diagnostic(odr_decode(),
+                                  &diagnostic, &num_diagnostic,
+                                  4, "scan");
+           Z_SRW_PDU *srw_pdu =
+               yaz_srw_get(odr_encode(),
+                           Z_SRW_scan_response);
+           Z_SRW_scanResponse *srw_res = srw_pdu->u.scan_response;
+           
+           srw_res->diagnostics = diagnostic;
+           srw_res->num_diagnostics = num_diagnostic;
+           send_srw_response(srw_pdu);
+           return;
+        }
+       else
+        {
+           send_to_srw_client_error(4, 0);
+        }
     }
     int len = 0;
     Z_GDU *p = z_get_HTTP_Response(odr_encode(), 400);