Oops Still need HAVE_XML2 in seshigh.c.
[yaz-moved-to-github.git] / server / seshigh.c
index 9ba52f6..ba96698 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 1995-2003, Index Data
  * See the file LICENSE for details.
  *
- * $Id: seshigh.c,v 1.134 2003-02-12 15:06:43 adam Exp $
+ * $Id: seshigh.c,v 1.142 2003-02-18 14:47:23 adam Exp $
  */
 
 /*
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <sys/types.h>
 #ifdef WIN32
+#include <io.h>
+#define S_ISREG(x) (x & _S_IFREG)
 #include <process.h>
+#include <sys/stat.h>
 #else
+#include <sys/stat.h>
 #include <unistd.h>
 #endif
 #include <assert.h>
@@ -177,7 +182,9 @@ void destroy_association(association *h)
     xfree(h);
     xmalloc_trav("session closed");
     if (control_block && control_block->one_shot)
+    {
        exit (0);
+    }
 }
 
 static void do_close_req(association *a, int reason, char *message,
@@ -198,7 +205,7 @@ static void do_close_req(association *a, int reason, char *message,
        *cls->closeReason = reason;
        cls->diagnosticInformation = message;
        process_z_response(a, req, &apdu);
-       iochan_settimeout(a->client_chan, 60);
+       iochan_settimeout(a->client_chan, 20);
     }
     else
     {
@@ -280,7 +287,7 @@ void ir_session(IOCHAN h, int event)
            /* We aren't speaking to this fellow */
            if (assoc->state == ASSOC_DEAD)
            {
-               yaz_log(LOG_LOG, "Closed connection after reject");
+               yaz_log(LOG_LOG, "Connection closed - end of session");
                cs_close(conn);
                destroy_association(assoc);
                iochan_destroy(h);
@@ -379,14 +386,12 @@ void ir_session(IOCHAN h, int event)
            {   /* restore mask for cs_get operation ... */
                iochan_clearflag(h, EVENT_OUTPUT|EVENT_INPUT);
                iochan_setflag(h, assoc->cs_get_mask);
-                yaz_log(LOG_LOG, "queue empty mask=%d", assoc->cs_get_mask);
                 if (assoc->state == ASSOC_DEAD)
                     iochan_setevent(assoc->client_chan, EVENT_TIMEOUT);
            }
             else
             {
                 assoc->cs_put_mask = EVENT_OUTPUT;
-                yaz_log(LOG_LOG, "queue not empty");
             }
            break;
        default:
@@ -459,9 +464,11 @@ static void srw_bend_fetch(association *assoc, int pos,
     rr.request_format_raw = yaz_oidval_to_z3950oid(assoc->decode,
                                                    CLASS_TRANSYN,
                                                    VAL_TEXT_XML);
-    rr.comp = odr_malloc(assoc->decode, sizeof(*rr.comp));
+    rr.comp = (Z_RecordComposition *)
+           odr_malloc(assoc->decode, sizeof(*rr.comp));
     rr.comp->which = Z_RecordComp_complex;
-    rr.comp->u.complex = odr_malloc(assoc->decode, sizeof(Z_CompSpec));
+    rr.comp->u.complex = (Z_CompSpec *)
+           odr_malloc(assoc->decode, sizeof(Z_CompSpec));
     rr.comp->u.complex->selectAlternativeSyntax = (bool_t *)
         odr_malloc(assoc->encode, sizeof(bool_t));
     *rr.comp->u.complex->selectAlternativeSyntax = 0;    
@@ -470,10 +477,10 @@ static void srw_bend_fetch(association *assoc, int pos,
     rr.comp->u.complex->num_recordSyntax = 0; 
     rr.comp->u.complex->recordSyntax = 0;
 
-    rr.comp->u.complex->generic = odr_malloc(assoc->decode,
-                                             sizeof(Z_Specification));
-    rr.comp->u.complex->generic->which = Z_Specification_uri;
-    rr.comp->u.complex->generic->u.uri = srw_req->recordSchema;
+    rr.comp->u.complex->generic = (Z_Specification *) 
+           odr_malloc(assoc->decode, sizeof(Z_Specification));
+    rr.comp->u.complex->generic->which = Z_Schema_uri;
+    rr.comp->u.complex->generic->schema.uri = srw_req->recordSchema;
     rr.comp->u.complex->generic->elementSpec = 0;
     
     rr.stream = assoc->encode;
@@ -496,7 +503,9 @@ static void srw_bend_fetch(association *assoc, int pos,
         record->recordData_buf = rr.record;
         record->recordData_len = rr.len;
         record->recordPosition = odr_intdup(o, pos);
-        record->recordSchema = odr_strdup(o, srw_req->recordSchema);
+        record->recordSchema = 0;
+        if (srw_req->recordSchema)
+            record->recordSchema = odr_strdup(o, srw_req->recordSchema);
     }
 }
 
@@ -507,6 +516,8 @@ static void srw_bend_search(association *assoc, request *req,
     char *base = "Default";
     bend_search_rr rr;
     Z_External *ext;
+    
+    yaz_log(LOG_LOG, "Got SRW SearchRetrieveRequest");
 
     if (!assoc->init)
         srw_bend_init(assoc);
@@ -514,7 +525,7 @@ static void srw_bend_search(association *assoc, request *req,
     rr.setname = "default";
     rr.replace_set = 1;
     rr.num_bases = 1;
-    rr.basenames = &base;
+    rr.basenames = &srw_req->database;
     rr.referenceId = 0;
 
     ext = (Z_External *) odr_malloc(assoc->decode, sizeof(*ext));
@@ -542,15 +553,17 @@ static void srw_bend_search(association *assoc, request *req,
     rr.errcode = 0;
     rr.errstring = 0;
     rr.search_info = 0;
+    yaz_log_zquery(rr.query);
     (assoc->init->bend_search)(assoc->backend, &rr);
     srw_res->numberOfRecords = odr_intdup(assoc->encode, rr.hits);
     if (rr.errcode)
     {
         srw_res->num_diagnostics = 1;
-        srw_res->diagnostics =
-            odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
+        srw_res->diagnostics = (Z_SRW_diagnostic *)
+           odr_malloc(assoc->encode, sizeof(*srw_res->diagnostics));
         srw_res->diagnostics[0].code = 
             odr_intdup(assoc->encode, rr.errcode);
+        srw_res->diagnostics[0].details = rr.errstring;
     }
     else
     {
@@ -567,7 +580,7 @@ static void srw_bend_search(association *assoc, request *req,
                 int j = 0;
                 if (start + number > rr.hits)
                     number = rr.hits - start + 1;
-                srw_res->records = 
+                srw_res->records = (Z_SRW_record *)
                     odr_malloc(assoc->encode,
                                number * sizeof(*srw_res->records));
                 for (i = 0; i<number; i++)
@@ -581,7 +594,6 @@ static void srw_bend_search(association *assoc, request *req,
                 srw_res->num_records = j;
                 if (!j)
                     srw_res->records = 0;
-                yaz_log(LOG_LOG, "got %d records", j);
             }
         }
     }
@@ -590,27 +602,77 @@ static void srw_bend_search(association *assoc, request *req,
 static void process_http_request(association *assoc, request *req)
 {
     Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
-    Z_HTTP_Header *hp;
     ODR o = assoc->encode;
-    Z_GDU *p;
+    Z_GDU *p = 0;
     Z_HTTP_Response *hres = 0;
     int keepalive = 1;
 
-#if 0
-    yaz_log(LOG_LOG, "HTTP Request. method=%s Version=%s Path=%s",
-            hreq->method, hreq->version, hreq->path);
-
-    for (hp = hreq->headers; hp; hp = hp->next)
-       yaz_log(LOG_LOG, "%s: %s", hp->name, hp->value);
-#endif
-
     if (!strcmp(hreq->method, "GET"))
     {
-        if (!strcmp(hreq->path, "/")) 
+#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);
+           }
+       }
+#endif
+       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 = odr_malloc(o, 400);
+            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"
@@ -620,12 +682,13 @@ static void process_http_request(association *assoc, request *req)
                      " <BODY>\n"
                      "  <P><A HREF=\"http://www.indexdata.dk/yaz/\">YAZ</A> " 
                      YAZ_VERSION "</P>\n"
+                     "%s"
                      " </BODY>\n"
-                     "</HTML>\n");
+                     "</HTML>\n", doclink);
             hres->content_len = strlen(hres->content_buf);
             z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
         }
-        else
+        if (!p)
         {
             p = z_get_HTTP_Response(o, 404);
         }
@@ -636,23 +699,25 @@ static void process_http_request(association *assoc, request *req)
                                                         "Content-Type");
         const char *soap_action = z_HTTP_header_lookup(hreq->headers,
                                                        "SOAPAction");
-        p = 0;  /* no response yet */
         if (content_type && soap_action && 
             !yaz_strcmp_del("text/xml", content_type, "; "))
         {
             Z_SOAP *soap_package = 0;
-            int ret;
+            int ret = -1;
             int http_code = 500;
 
             static Z_SOAP_Handler soap_handlers[2] = {
-                {"http://www.loc.gov/zing/srw/v1.0/", 0, yaz_srw_codec},
+#if HAVE_XML2
+                {"http://www.loc.gov/zing/srw/v1.0/", 0,
+                                        (Z_SOAP_fun) yaz_srw_codec},
+#endif
                 {0, 0, 0}
             };
-
             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)
             {
@@ -664,20 +729,40 @@ static void process_http_request(association *assoc, request *req)
                     Z_SRW_searchRetrieve *res =
                         yaz_srw_get(assoc->encode,
                                     Z_SRW_searchRetrieve_response);
-                    
-                    srw_bend_search(assoc, req, sr->u.request, res->u.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;
                 }
             }
-
+#endif
             p = z_get_HTTP_Response(o, 200);
             hres = p->u.HTTP_Response;
             ret = z_soap_codec(assoc->encode, &soap_package,
                                &hres->content_buf, &hres->content_len,
                                soap_handlers);
             hres->code = http_code;
+            z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/xml");
         }
         if (!p) /* still no response ? */
             p = z_get_HTTP_Response(o, 500);
@@ -715,6 +800,16 @@ static void process_http_request(association *assoc, request *req)
     }
     else
     {
+        int t;
+        const char *alive = z_HTTP_header_lookup(hreq->headers, "Keep-Alive");
+
+        if (alive && isdigit(*alive))
+            t = atoi(alive);
+        else
+            t = 30;
+        if (t < 0 || t > 3600)
+            t = 3600;
+        iochan_settimeout(assoc->client_chan,t);
         z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
     }
     process_gdu_response(assoc, req, p);
@@ -756,6 +851,8 @@ static int process_z_request(association *assoc, request *req, char **msg)
     switch (req->apdu_request->which)
     {
     case Z_APDU_initRequest:
+        iochan_settimeout(assoc->client_chan,
+                          statserv_getcontrol()->idle_timeout * 60);
        res = process_initRequest(assoc, req); break;
     case Z_APDU_searchRequest:
        res = process_searchRequest(assoc, req, &fd); break;