Added cs_get_SSL. yaz-client-ssl prints peer info
[yaz-moved-to-github.git] / src / seshigh.c
index 05cc464..1bdede6 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 1995-2003, Index Data
+ * Copyright (c) 1995-2004, Index Data
  * See the file LICENSE for details.
  *
- * $Id: seshigh.c,v 1.1 2003-10-27 12:21:35 adam Exp $
+ * $Id: seshigh.c,v 1.23 2004-03-29 15:09:14 adam Exp $
  */
 
 /*
@@ -271,7 +271,7 @@ void ir_session(IOCHAN h, int event)
            destroy_association(assoc);
            iochan_destroy(h);
        }
-       iochan_clearflag (h, EVENT_OUTPUT|EVENT_OUTPUT);
+       iochan_clearflag (h, EVENT_OUTPUT);
        if (conn->io_pending) 
        {   /* cs_accept didn't complete */
            assoc->cs_accept_mask = 
@@ -353,10 +353,11 @@ void ir_session(IOCHAN h, int event)
                return;
            }
            req->request_mem = odr_extract_mem(assoc->decode);
-           if (assoc->print && !z_GDU(assoc->print, &req->gdu_request, 0, 0))
-           {
-               yaz_log(LOG_WARN, "ODR print error: %s", 
-                   odr_errmsg(odr_geterror(assoc->print)));
+           if (assoc->print) 
+            {
+               if (!z_GDU(assoc->print, &req->gdu_request, 0, 0))
+                   yaz_log(LOG_WARN, "ODR print error: %s", 
+                      odr_errmsg(odr_geterror(assoc->print)));
                odr_reset(assoc->print);
            }
            request_enq(&assoc->incoming, req);
@@ -470,6 +471,7 @@ static int srw_bend_init(association *assoc)
     ce = yaz_set_proposal_charneg(assoc->decode, &encoding, 1, 0, 0, 1);
     assoc->init->charneg_request = ce->u.charNeg3;
 #endif
+    assoc->backend = 0;
     if (!(binitres = (*cb->bend_init)(assoc->init)))
     {
        yaz_log(LOG_WARN, "Bad response from backend.");
@@ -546,12 +548,14 @@ static int srw_bend_fetch(association *assoc, int pos,
 
 static void srw_bend_search(association *assoc, request *req,
                             Z_SRW_searchRetrieveRequest *srw_req,
-                            Z_SRW_searchRetrieveResponse *srw_res)
+                            Z_SRW_searchRetrieveResponse *srw_res,
+                           int *http_code)
 {
     int srw_error = 0;
     bend_search_rr rr;
     Z_External *ext;
     
+    *http_code = 200;
     yaz_log(LOG_LOG, "Got SRW SearchRetrieveRequest");
     yaz_log(LOG_DEBUG, "srw_bend_search");
     if (!assoc->init)
@@ -561,12 +565,8 @@ static void srw_bend_search(association *assoc, request *req,
         {
             srw_error = 3;  /* assume Authentication error */
 
-            srw_res->num_diagnostics = 1;
-            srw_res->diagnostics = (Z_SRW_diagnostic *)
-                odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
-            srw_res->diagnostics[0].code = 
-                odr_intdup(assoc->encode, srw_error);
-            srw_res->diagnostics[0].details = 0;
+           yaz_add_srw_diagnostic(assoc->encode, &srw_res->diagnostics,
+                                  &srw_res->num_diagnostics, 1, 0);
             return;
         }
     }
@@ -632,9 +632,8 @@ static void srw_bend_search(association *assoc, request *req,
         srw_res->num_diagnostics = 1;
         srw_res->diagnostics = (Z_SRW_diagnostic *)
            odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
-        srw_res->diagnostics[0].code = 
-            odr_intdup(assoc->encode, srw_error);
-        srw_res->diagnostics[0].details = 0;
+       yaz_mk_std_diagnostic(assoc->encode,
+                             srw_res->diagnostics, srw_error, 0);
         return;
     }
     
@@ -654,16 +653,19 @@ static void srw_bend_search(association *assoc, request *req,
     if (rr.errcode)
     {
         yaz_log(LOG_DEBUG, "bend_search returned Bib-1 code %d", rr.errcode);
+       if (rr.errcode == 109) /* database unavailable */
+       {
+           *http_code = 404;
+           return;
+       }
         srw_res->num_diagnostics = 1;
         srw_res->diagnostics = (Z_SRW_diagnostic *)
            odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
-        srw_res->diagnostics[0].code = 
-            odr_intdup(assoc->encode, 
-                       yaz_diag_bib1_to_srw (rr.errcode));
-        srw_res->diagnostics[0].details = rr.errstring;
-        yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %d",
-                *srw_res->diagnostics[0].code);
-                
+       yaz_mk_std_diagnostic(assoc->encode, srw_res->diagnostics,
+                             yaz_diag_bib1_to_srw (rr.errcode),
+                             rr.errstring);
+        yaz_log(LOG_DEBUG, "srw_bend_search returned SRW error %s",
+                srw_res->diagnostics[0].uri);
     }
     else
     {
@@ -709,10 +711,11 @@ static void srw_bend_search(association *assoc, request *req,
                         srw_res->diagnostics = (Z_SRW_diagnostic *)
                             odr_malloc(assoc->encode, 
                                        sizeof(*srw_res->diagnostics));
-                        srw_res->diagnostics[0].code = 
-                            odr_intdup(assoc->encode, 
-                                       yaz_diag_bib1_to_srw (errcode));
-                        srw_res->diagnostics[0].details = rr.errstring;
+
+                       yaz_mk_std_diagnostic(assoc->encode, 
+                                             srw_res->diagnostics,
+                                             yaz_diag_bib1_to_srw (errcode),
+                                             rr.errstring);
                         break;
                     }
                     if (srw_res->records[j].recordData_buf)
@@ -726,17 +729,20 @@ static void srw_bend_search(association *assoc, request *req,
     }
 }
 
-
 static void srw_bend_explain(association *assoc, request *req,
                              Z_SRW_explainRequest *srw_req,
-                             Z_SRW_explainResponse *srw_res)
+                             Z_SRW_explainResponse *srw_res,
+                            int *http_code)
 {
     yaz_log(LOG_LOG, "Got SRW ExplainRequest");
+    *http_code = 404;
     if (!assoc->init)
     {
         yaz_log(LOG_DEBUG, "srw_bend_init");
         if (!srw_bend_init(assoc))
+       {
             return;
+       }
     }
     if (assoc->init && assoc->init->bend_explain)
     {
@@ -746,430 +752,152 @@ static void srw_bend_explain(association *assoc, request *req,
         rr.decode = assoc->decode;
         rr.print = assoc->print;
         rr.explain_buf = 0;
+       rr.database = srw_req->database;
+       rr.schema = "http://explain.z3950.org/dtd/2.0/";
         (*assoc->init->bend_explain)(assoc->backend, &rr);
         if (rr.explain_buf)
         {
-            srw_res->explainData_buf = rr.explain_buf;
-            srw_res->explainData_len = strlen(rr.explain_buf);
-        }
-    }
-}
-
-static int hex_digit (int ch)
-{
-    if (ch >= '0' && ch <= '9')
-        return ch - '0';
-    else if (ch >= 'a' && ch <= 'f')
-        return ch - 'a'+10;
-    else if (ch >= 'A' && ch <= 'F')
-        return ch - 'A'+10;
-    return 0;
-}
-
-static char *uri_val(const char *path, const char *name, ODR o)
-{
-    size_t nlen = strlen(name);
-    if (*path != '?')
-        return 0;
-    path++;
-    while (path && *path)
-    {
-        const char *p1 = strchr(path, '=');
-        if (!p1)
-            break;
-        if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
-        {
-            size_t i = 0;
-            char *ret;
-            
-            path = p1 + 1;
-            p1 = strchr(path, '&');
-            if (!p1)
-                p1 = strlen(path) + path;
-            ret = odr_malloc(o, p1 - path + 1);
-            while (*path && *path != '&')
-            {
-                if (*path == '+')
-                {
-                    ret[i++] = ' ';
-                    path++;
-                }
-                else if (*path == '%' && path[1] && path[2])
-                {
-                    ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
-                    path = path + 3;
-                }
-                else
-                    ret[i++] = *path++;
-            }
-            ret[i] = '\0';
-            return ret;
+           int packing = Z_SRW_recordPacking_string;
+           if (srw_req->recordPacking && 
+               !strcmp(srw_req->recordPacking, "xml"))
+               packing = Z_SRW_recordPacking_XML;
+           srw_res->record.recordSchema = 0;
+           srw_res->record.recordPacking = packing;
+            srw_res->record.recordData_buf = rr.explain_buf;
+            srw_res->record.recordData_len = strlen(rr.explain_buf);
+           srw_res->record.recordPosition = 0;
+           *http_code = 200;
         }
-        path = strchr(p1, '&');
-        if (path)
-            path++;
     }
-    return 0;
-}
-
-void uri_val_int(const char *path, const char *name, ODR o, int **intp)
-{
-    const char *v = uri_val(path, name, o);
-    if (v)
-        *intp = odr_intdup(o, atoi(v));
 }
 
 static void process_http_request(association *assoc, request *req)
 {
     Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
     ODR o = assoc->encode;
+    int r = 2;  /* 2=NOT TAKEN, 1=TAKEN, 0=SOAP TAKEN */
+    Z_SRW_PDU *sr = 0;
+    Z_SOAP *soap_package = 0;
     Z_GDU *p = 0;
+    char *charset = 0;
     Z_HTTP_Response *hres = 0;
     int keepalive = 1;
+    char *stylesheet = 0;
+    Z_SRW_diagnostic *diagnostic = 0;
+    int num_diagnostic = 0;
 
-    if (!strcmp(hreq->method, "GET"))
+    if (!strcmp(hreq->path, "/test")) 
+    {  
+       p = z_get_HTTP_Response(o, 200);
+       hres = p->u.HTTP_Response;
+       hres->content_buf = "1234567890\n";
+       hres->content_len = strlen(hres->content_buf);
+       r = 1;
+    }
+    if (r == 2)
     {
-        char *db = "Default";
-        const char *p0 = hreq->path, *p1;
-#if HAVE_XML2
-        int ret = -1;
-        char *charset = 0;
-        Z_SOAP *soap_package = 0;
-        static Z_SOAP_Handler soap_handlers[2] = {
-            {"http://www.loc.gov/zing/srw/v1.0/", 0,
-             (Z_SOAP_fun) yaz_srw_codec},
-            {0, 0, 0}
-        };
-#endif
-        
-        if (*p0 == '/')
-            p0++;
-        p1 = strchr(p0, '?');
-        if (!p1)
-            p1 = p0 + strlen(p0);
-        if (p1 != p0)
-        {
-            db = odr_malloc(assoc->decode, p1 - p0 + 1);
-            memcpy (db, p0, p1 - p0);
-            db[p1 - p0] = '\0';
-        }
-#if HAVE_XML2
-        if (p1 && *p1 == '?' && p1[1])
-        {
-            Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
-            Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_searchRetrieve_request);
-            char *query = uri_val(p1, "query", o);
-            char *pQuery = uri_val(p1, "pQuery", o);
-            char *sortKeys = uri_val(p1, "sortKeys", o);
-            
-            if (query)
-            {
-                sr->u.request->query_type = Z_SRW_query_type_cql;
-                sr->u.request->query.cql = query;
-            }
-            if (pQuery)
-            {
-                sr->u.request->query_type = Z_SRW_query_type_pqf;
-                sr->u.request->query.pqf = pQuery;
-            }
-            if (sortKeys)
-            {
-                sr->u.request->sort_type = Z_SRW_sort_type_sort;
-                sr->u.request->sort.sortKeys = sortKeys;
-            }
-            sr->u.request->recordSchema = uri_val(p1, "recordSchema", o);
-            sr->u.request->recordPacking = uri_val(p1, "recordPacking", o);
-            if (!sr->u.request->recordPacking)
-                sr->u.request->recordPacking = "xml";
-            uri_val_int(p1, "maximumRecords", o, 
-                        &sr->u.request->maximumRecords);
-            uri_val_int(p1, "startRecord", o,
-                        &sr->u.request->startRecord);
-            if (sr->u.request->startRecord)
-                yaz_log(LOG_LOG, "startRecord=%d", *sr->u.request->startRecord);
-            sr->u.request->database = db;
-            srw_bend_search(assoc, req, sr->u.request, res->u.response);
-            
-            soap_package = odr_malloc(o, sizeof(*soap_package));
-            soap_package->which = Z_SOAP_generic;
-
-            soap_package->u.generic =
-                odr_malloc(o, sizeof(*soap_package->u.generic));
-
-            soap_package->u.generic->p = res;
-            soap_package->u.generic->ns = soap_handlers[0].ns;
-            soap_package->u.generic->no = 0;
-            
-            soap_package->ns = "SRU";
-
-            p = z_get_HTTP_Response(o, 200);
-            hres = p->u.HTTP_Response;
-
-            ret = z_soap_codec_enc(assoc->encode, &soap_package,
-                                   &hres->content_buf, &hres->content_len,
-                                   soap_handlers, charset);
-            if (!charset)
-                z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
-            else
-            {
-                char ctype[60];
-                strcpy(ctype, "text/xml; charset=");
-                strcat(ctype, charset);
-                z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
-            }
+       r = yaz_srw_decode(hreq, &sr, &soap_package, assoc->decode, &charset);
+       yaz_log(LOG_DEBUG, "yaz_srw_decode returned %d", r);
+    }
+    if (r == 2)  /* not taken */
+    {
+       r = yaz_sru_decode(hreq, &sr, &soap_package, assoc->decode, &charset,
+                          &diagnostic, &num_diagnostic);
+       yaz_log(LOG_DEBUG, "yaz_sru_decode returned %d", r);
+    }
+    if (r == 0)  /* decode SRW/SRU OK .. */
+    {
+       int http_code = 200;
+       if (sr->which == Z_SRW_searchRetrieve_request)
+       {
+           Z_SRW_PDU *res =
+               yaz_srw_get(assoc->encode, Z_SRW_searchRetrieve_response);
 
-        }
-        else
-        {
+           stylesheet = sr->u.request->stylesheet;
+           if (num_diagnostic)
+           {
+               res->u.response->diagnostics = diagnostic;
+               res->u.response->num_diagnostics = num_diagnostic;
+           }
+           else
+           {
+               srw_bend_search(assoc, req, sr->u.request, res->u.response, 
+                               &http_code);
+           }
+           if (http_code == 200)
+               soap_package->u.generic->p = res;
+       }
+       else if (sr->which == Z_SRW_explain_request)
+       {
             Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_explain_response);
-            Z_SRW_PDU *sr = yaz_srw_get(o, Z_SRW_explain_request);
-
-            srw_bend_explain(assoc, req, sr->u.explain_request,
-                            res->u.explain_response);
-
-            if (res->u.explain_response->explainData_buf)
-            {
-                soap_package = odr_malloc(o, sizeof(*soap_package));
-                soap_package->which = Z_SOAP_generic;
-                
-                soap_package->u.generic =
-                    odr_malloc(o, sizeof(*soap_package->u.generic));
-                
-                soap_package->u.generic->p = res;
-                soap_package->u.generic->ns = soap_handlers[0].ns;
-                soap_package->u.generic->no = 0;
-                
-                soap_package->ns = "SRU";
-                
-                p = z_get_HTTP_Response(o, 200);
-                hres = p->u.HTTP_Response;
-                
-                ret = z_soap_codec_enc(assoc->encode, &soap_package,
-                                       &hres->content_buf, &hres->content_len,
-                                       soap_handlers, charset);
-                if (!charset)
-                    z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
-                else
-                {
-                    char ctype[60];
-                    strcpy(ctype, "text/xml; charset=");
-                    strcat(ctype, charset);
-                    z_HTTP_header_add(o, &hres->headers, "Content-Type",
-                                      ctype);
-                }
-            }
-        }
-#endif
-#ifdef DOCDIR
-       if (strlen(hreq->path) >= 5 && strlen(hreq->path) < 80 &&
-                        !memcmp(hreq->path, "/doc/", 5))
-        {
-           FILE *f;
-            char fpath[120];
-
-           strcpy(fpath, DOCDIR);
-           strcat(fpath, hreq->path+4);
-           f = fopen(fpath, "rb");
-           if (f) {
-                struct stat sbuf;
-                if (fstat(fileno(f), &sbuf) || !S_ISREG(sbuf.st_mode))
-                {
-                    fclose(f);
-                    f = 0;
-                }
-            }
-            if (f)
-            {
-               long sz;
-               fseek(f, 0L, SEEK_END);
-               sz = ftell(f);
-               if (sz >= 0 && sz < 500000)
-               {
-                   const char *ctype = "application/octet-stream";
-                   const char *cp;
-
-                    p = z_get_HTTP_Response(o, 200);
-                    hres = p->u.HTTP_Response;
-                   hres->content_buf = (char *) odr_malloc(o, sz + 1);
-                   hres->content_len = sz;
-                   fseek(f, 0L, SEEK_SET);
-                   fread(hres->content_buf, 1, sz, f);
-                   if ((cp = strrchr(fpath, '.'))) {
-                       cp++;
-                       if (!strcmp(cp, "png"))
-                           ctype = "image/png";
-                       else if (!strcmp(cp, "gif"))
-                           ctype = "image/gif";
-                       else if (!strcmp(cp, "xml"))
-                           ctype = "text/xml";
-                       else if (!strcmp(cp, "html"))
-                           ctype = "text/html";
-                   }
-                    z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
-               }
-               fclose(f);
+           stylesheet = sr->u.explain_request->stylesheet;
+           if (num_diagnostic)
+           {   
+               res->u.explain_response->diagnostics = diagnostic;
+               res->u.explain_response->num_diagnostics = num_diagnostic;
            }
+           srw_bend_explain(assoc, req, sr->u.explain_request,
+                            res->u.explain_response, &http_code);
+           if (http_code == 200)
+               soap_package->u.generic->p = res;
        }
-#endif
-
-#if 0
-       if (!strcmp(hreq->path, "/")) 
-        {
-#ifdef DOCDIR
-            struct stat sbuf;
-#endif
-            const char *doclink = "";
-            p = z_get_HTTP_Response(o, 200);
-            hres = p->u.HTTP_Response;
-            hres->content_buf = (char *) odr_malloc(o, 400);
-#ifdef DOCDIR
-            if (stat(DOCDIR "/yaz.html", &sbuf) == 0 && S_ISREG(sbuf.st_mode))
-                doclink = "<P><A HREF=\"/doc/yaz.html\">Documentation</A></P>";
-#endif
-            sprintf (hres->content_buf, 
-                     "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
-                     "<HTML>\n"
-                     " <HEAD>\n"
-                     "  <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
-                     " </HEAD>\n"
-                     " <BODY>\n"
-                     "  <P><A HREF=\"http://www.indexdata.dk/yaz/\">YAZ</A> " 
-                     YAZ_VERSION "</P>\n"
-                     "%s"
-                     " </BODY>\n"
-                     "</HTML>\n", doclink);
-            hres->content_len = strlen(hres->content_buf);
-            z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
-        }
-#endif
-
-        if (!p)
-        {
-            p = z_get_HTTP_Response(o, 404);
-        }
-    }
-    else if (!strcmp(hreq->method, "POST"))
-    {
-        const char *content_type = z_HTTP_header_lookup(hreq->headers,
-                                                        "Content-Type");
-        if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
-        {
-            Z_SOAP *soap_package = 0;
-            int ret = -1;
-            int http_code = 500;
-            const char *charset_p = 0;
-            char *charset = 0;
-
-            static Z_SOAP_Handler soap_handlers[2] = {
+       else if (sr->which == Z_SRW_scan_request)
+       {
+            Z_SRW_PDU *res = yaz_srw_get(o, Z_SRW_scan_response);
+           stylesheet = sr->u.scan_request->stylesheet;
+           if (num_diagnostic)
+           {   
+               res->u.scan_response->diagnostics = diagnostic;
+               res->u.scan_response->num_diagnostics = num_diagnostic;
+           }
+           yaz_add_srw_diagnostic(o, 
+                                  &res->u.scan_response->diagnostics,
+                                  &res->u.scan_response->num_diagnostics,
+                                  4, "scan");
+           if (http_code == 200)
+               soap_package->u.generic->p = res;
+       }
+       else
+       {
+                yaz_log(LOG_LOG, "generate soap error");
+           http_code = 500;
+           z_soap_error(assoc->encode, soap_package,
+                        "SOAP-ENV:Client", "Bad method", 0); 
+       }
+       if (http_code == 200 || http_code == 500)
+       {
+           static Z_SOAP_Handler soap_handlers[3] = {
 #if HAVE_XML2
+               {"http://www.loc.gov/zing/srw/", 0,
+                (Z_SOAP_fun) yaz_srw_codec},
                 {"http://www.loc.gov/zing/srw/v1.0/", 0,
                  (Z_SOAP_fun) yaz_srw_codec},
 #endif
-                {0, 0, 0}
-            };
-            if ((charset_p = strstr(content_type, "; charset=")))
-            {
-                int i = 0;
-                charset_p += 10;
-                while (i < 20 && charset_p[i] &&
-                       !strchr("; \n\r", charset_p[i]))
-                    i++;
-                charset = odr_malloc(assoc->encode, i+1);
-                memcpy(charset, charset_p, i);
-                charset[i] = '\0';
-                yaz_log(LOG_LOG, "SOAP encoding %s", charset);
-            }
-            ret = z_soap_codec(assoc->decode, &soap_package, 
-                               &hreq->content_buf, &hreq->content_len,
-                               soap_handlers);
-#if HAVE_XML2
-            if (!ret && soap_package->which == Z_SOAP_generic &&
-                soap_package->u.generic->no == 0)
-            {
-                /* SRW package */
-                Z_SRW_PDU *sr = soap_package->u.generic->p;
-                
-                if (sr->which == Z_SRW_searchRetrieve_request)
-                {
-                    Z_SRW_PDU *res =
-                        yaz_srw_get(assoc->encode,
-                                    Z_SRW_searchRetrieve_response);
-
-                    if (!sr->u.request->database)
-                    {
-                        const char *p0 = hreq->path, *p1;
-                        if (*p0 == '/')
-                            p0++;
-                        p1 = strchr(p0, '?');
-                        if (!p1)
-                            p1 = p0 + strlen(p0);
-                        if (p1 != p0)
-                        {
-                            sr->u.request->database =
-                                odr_malloc(assoc->decode, p1 - p0 + 1);
-                            memcpy (sr->u.request->database, p0, p1 - p0);
-                            sr->u.request->database[p1 - p0] = '\0';
-                        }
-                        else
-                            sr->u.request->database = "Default";
-                    }
-                    srw_bend_search(assoc, req, sr->u.request,
-                                    res->u.response);
-                    
-                    soap_package->u.generic->p = res;
-                    http_code = 200;
-                }
-                else if (sr->which == Z_SRW_explain_request)
-                {
-                    Z_SRW_PDU *res =
-                        yaz_srw_get(assoc->encode, Z_SRW_explain_response);
-
-                    srw_bend_explain(assoc, req, sr->u.explain_request,
-                                     res->u.explain_response);
-                    if (!res->u.explain_response->explainData_buf)
-                    {
-                        z_soap_error(assoc->encode, soap_package,
-                                     "SOAP-ENV:Client", "Explain Not Supported", 0);
-                    }
-                    else
-                    {
-                        soap_package->u.generic->p = res;
-                        http_code = 200;
-                    }
-                }
-                else
-                {
-                    z_soap_error(assoc->encode, soap_package,
-                                 "SOAP-ENV:Client", "Bad method", 0); 
-                }
-            }
-#endif
-            p = z_get_HTTP_Response(o, 200);
-            hres = p->u.HTTP_Response;
-            ret = z_soap_codec_enc(assoc->encode, &soap_package,
-                                   &hres->content_buf, &hres->content_len,
-                                   soap_handlers, charset);
-            hres->code = http_code;
-            if (!charset)
-                z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
-            else
-            {
-                char ctype[60];
-                strcpy(ctype, "text/xml; charset=");
-                strcat(ctype, charset);
-                z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
-            }
-        }
-        if (!p) /* still no response ? */
-            p = z_get_HTTP_Response(o, 500);
+               {0, 0, 0}
+           };
+           char ctype[60];
+           int ret;
+           p = z_get_HTTP_Response(o, 200);
+           hres = p->u.HTTP_Response;
+           ret = z_soap_codec_enc_xsl(assoc->encode, &soap_package,
+                                      &hres->content_buf, &hres->content_len,
+                                      soap_handlers, charset, stylesheet);
+           hres->code = http_code;
+
+           strcpy(ctype, "text/xml");
+           if (charset)
+           {
+               strcat(ctype, "; charset=");
+               strcat(ctype, charset);
+           }
+           z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
+       }
+       else
+           p = z_get_HTTP_Response(o, http_code);
     }
-    else
-    {
-        p = z_get_HTTP_Response(o, 405);
-        hres = p->u.HTTP_Response;
 
-        z_HTTP_header_add(o, &hres->headers, "Allow", "GET, POST");
-    }
+    if (p == 0)
+       p = z_get_HTTP_Response(o, 500);
     hres = p->u.HTTP_Response;
     if (!strcmp(hreq->version, "1.0")) 
     {
@@ -1193,6 +921,7 @@ static void process_http_request(association *assoc, request *req)
     {
         z_HTTP_header_add(o, &hres->headers, "Connection", "close");
         assoc->state = ASSOC_DEAD;
+       assoc->cs_get_mask = 0;
     }
     else
     {
@@ -1382,10 +1111,11 @@ static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
 {
     odr_setbuf(assoc->encode, req->response, req->size_response, 1);
 
-    if (assoc->print && !z_GDU(assoc->print, &res, 0, 0))
+    if (assoc->print)
     {
-       yaz_log(LOG_WARN, "ODR print error: %s", 
-           odr_errmsg(odr_geterror(assoc->print)));
+       if (!z_GDU(assoc->print, &res, 0, 0))
+           yaz_log(LOG_WARN, "ODR print error: %s", 
+               odr_errmsg(odr_geterror(assoc->print)));
        odr_reset(assoc->print);
     }
     if (!z_GDU(assoc->encode, &res, 0, 0))
@@ -1443,7 +1173,7 @@ static Z_APDU *process_initRequest(association *assoc, request *reqb)
     Z_APDU *apdu = zget_APDU(assoc->encode, Z_APDU_initResponse);
     Z_InitResponse *resp = apdu->u.initResponse;
     bend_initresult *binitres;
-
+    char *version;
     char options[140];
 
     yaz_log(LOG_LOG, "Got initRequest");
@@ -1463,10 +1193,12 @@ static Z_APDU *process_initRequest(association *assoc, request *reqb)
     {
         Z_CharSetandLanguageNegotiation *negotiation =
             yaz_get_charneg_record (req->otherInfo);
-        if (negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
+        if (negotiation &&
+           negotiation->which == Z_CharSetandLanguageNegotiation_proposal)
             assoc->init->charneg_request = negotiation;
     }
     
+    assoc->backend = 0;
     if (!(binitres = (*cb->bend_init)(assoc->init)))
     {
        yaz_log(LOG_WARN, "Bad response from backend.");
@@ -1557,7 +1289,7 @@ static Z_APDU *process_initRequest(association *assoc, request *reqb)
     if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
     {
        ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
-       assoc->version = 2; /* 1 & 2 are equivalent */
+       assoc->version = 1; /* 1 & 2 are equivalent */
     }
     if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
     {
@@ -1581,39 +1313,21 @@ static Z_APDU *process_initRequest(association *assoc, request *reqb)
     resp->preferredMessageSize = &assoc->preferredMessageSize;
     resp->maximumRecordSize = &assoc->maximumRecordSize;
 
-    resp->implementationName = "GFS/YAZ";
+    resp->implementationId = odr_prepend(assoc->encode,
+               assoc->init->implementation_id,
+               resp->implementationId);
 
-    if (assoc->init->implementation_id)
-    {
-       char *nv = (char *)
-           odr_malloc (assoc->encode,
-                       strlen(assoc->init->implementation_id) + 10 + 
-                              strlen(resp->implementationId));
-       sprintf (nv, "%s / %s",
-                resp->implementationId, assoc->init->implementation_id);
-        resp->implementationId = nv;
-    }
-    if (assoc->init->implementation_name)
-    {
-       char *nv = (char *)
-           odr_malloc (assoc->encode,
-                       strlen(assoc->init->implementation_name) + 10 + 
-                              strlen(resp->implementationName));
-       sprintf (nv, "%s / %s",
-                resp->implementationName, assoc->init->implementation_name);
-        resp->implementationName = nv;
-    }
-    if (assoc->init->implementation_version)
-    {
-       char *nv = (char *)
-           odr_malloc (assoc->encode,
-                       strlen(assoc->init->implementation_version) + 10 + 
-                              strlen(resp->implementationVersion));
-       sprintf (nv, "YAZ %s / %s",
-                resp->implementationVersion,
-                assoc->init->implementation_version);
-        resp->implementationVersion = nv;
-    }
+    resp->implementationName = odr_prepend(assoc->encode,
+               assoc->init->implementation_name,
+               odr_prepend(assoc->encode, "GFS", resp->implementationName));
+
+    version = odr_strdup(assoc->encode, "$Revision: 1.23 $");
+    if (strlen(version) > 10)  /* check for unexpanded CVS strings */
+       version[strlen(version)-2] = '\0';
+    resp->implementationVersion = odr_prepend(assoc->encode,
+               assoc->init->implementation_version,
+               odr_prepend(assoc->encode, &version[11],
+                           resp->implementationVersion));
 
     if (binitres->errcode)
     {
@@ -1702,6 +1416,7 @@ static Z_External *init_diagnostics(ODR odr, int error, char *addinfo)
 
     e->which = Z_DiagnosticFormat_s_defaultDiagRec;
     e->u.defaultDiagRec = justdiag(odr, error, addinfo);
+    e->message = 0;
     return x;
 }
 
@@ -1848,13 +1563,14 @@ static Z_Records *pack_records(association *a, char *setname, int start,
        if (freq.len >= 0)
            this_length = freq.len;
        else
-           this_length = odr_total(a->encode) - total_length;
-       yaz_log(LOG_DEBUG, "  fetched record, len=%d, total=%d",
-           this_length, total_length);
-       if (this_length + total_length > a->preferredMessageSize)
+           this_length = odr_total(a->encode) - total_length - dumped_records;
+       yaz_log(LOG_DEBUG, "  fetched record, len=%d, total=%d dumped=%d",
+           this_length, total_length, dumped_records);
+       if (a->preferredMessageSize > 0 &&
+               this_length + total_length > a->preferredMessageSize)
        {
            /* record is small enough, really */
-           if (this_length <= a->preferredMessageSize)
+           if (this_length <= a->preferredMessageSize && recno > start)
            {
                yaz_log(LOG_DEBUG, "  Dropped last normal-sized record");
                *pres = Z_PRES_PARTIAL_2;
@@ -1944,6 +1660,7 @@ static Z_APDU *process_searchRequest(association *assoc, request *reqb,
        bsrr->basenames = req->databaseNames;
        bsrr->query = req->query;
        bsrr->stream = assoc->encode;
+       nmem_transfer(bsrr->stream->mem, reqb->request_mem);
        bsrr->decode = assoc->decode;
        bsrr->print = assoc->print;
        bsrr->errcode = 0;