Added support for file access in GFS to facilitate static
authorAdam Dickmeiss <adam@indexdata.dk>
Wed, 15 Mar 2006 13:32:05 +0000 (13:32 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Wed, 15 Mar 2006 13:32:05 +0000 (13:32 +0000)
web pages, such XSL/CSS/HTML files.

doc/gfs-virtual.xml
etc/yazgfs.xml
src/Makefile.am
src/mime.c [new file with mode: 0644]
src/mime.h [new file with mode: 0644]
src/seshigh.c
src/session.h
src/statserv.c
win/makefile

index 340b641..62e8a0b 100644 (file)
@@ -1,5 +1,5 @@
 <!-- 
-   $Id: gfs-virtual.xml,v 1.3 2005-08-05 09:36:15 adam Exp $
+   $Id: gfs-virtual.xml,v 1.4 2006-03-15 13:32:05 adam Exp $
    Description of the virtual host mechanism in YAZ GFS
    Included in both manual and man page for yaz-ztest
 -->
     </para>
    </listitem>
   </varlistentry>
+
+  <varlistentry><term>element <literal>stylesheet</literal> (optional)</term>
+   <listitem>
+    <para>
+     Specifies the stylesheet reference to be part of SRU HTTP responses
+     when the client does not specify one. If neither this is given, nor
+     the client specifies one, no stylesheet reference is part of the
+     SRU HTTP response.
+    </para>
+   </listitem>
+  </varlistentry>
+   
+  <varlistentry><term>element <literal>docpath</literal> (optional)</term>
+   <listitem>
+    <para>
+     Specifies a path for local file access using HTTP. All URLs with
+     a leading prefix (/ exluded) that matches the value of docpath
+     are used for file access. For example, if the server is to offer
+     access in directory <literal>xsl</literal>, the docpath would be
+     <literal>xsl</literal> and all URLs of the form
+     <literal>http://host/exl</literal> will result in a local file access.
+    </para>
+   </listitem>
+  </varlistentry>
    
   <varlistentry><term>element <literal>explain</literal> (optional)</term>
    <listitem>
index 8dbc21a..72f1272 100644 (file)
@@ -1,12 +1,14 @@
-<!-- $Id: yazgfs.xml,v 1.1 2005-12-16 15:01:25 adam Exp $ -->
+<!-- $Id: yazgfs.xml,v 1.2 2006-03-15 13:32:05 adam Exp $ -->
 <!-- sample YAZ GFS config file .. see 
   http://indexdata.dk/yaz/doc/server.vhosts.tkl -->
 <yazgfs>
   <listen id="public1">tcp:@:9000</listen>
-  <server id="server1">
+  <server id="server1" listenref="public1">
      <directory>.</directory> <!-- directory where backend is running -->
      <config>zebra.cfg</config>
      <cql2rpn>pqf.properties</cql2rpn>
+     <docpath>xsl</docpath>
+     <stylesheet>xsl/default.xsl</stylesheet>
      <explain xmlns="http://explain.z3950.org/dtd/2.0/">
         <serverInfo>
            <host>myserver.org</host>
index 88c71cb..090f5ff 100644 (file)
@@ -1,6 +1,6 @@
 ## This file is part of the YAZ toolkit.
 ## Copyright (C) 1994-2005, Index Data, All rights reserved.
-## $Id: Makefile.am,v 1.28 2006-03-13 11:59:27 adam Exp $
+## $Id: Makefile.am,v 1.29 2006-03-15 13:32:05 adam Exp $
 
 YAZ_VERSION_INFO=2:0:0
 
@@ -66,7 +66,8 @@ libyaz_la_SOURCES=version.c options.c log.c marcdisp.c oid.c wrbuf.c \
   cqlstrer.c querytowrbuf.c \
   eventl.c seshigh.c statserv.c requestq.c tcpdchk.c \
   eventl.h service.c service.h session.h test.c \
-  xmlquery.c
+  xmlquery.c \
+  mime.c mime.h
 
 libyaz_la_LDFLAGS=-version-info $(YAZ_VERSION_INFO)
 
diff --git a/src/mime.c b/src/mime.c
new file mode 100644 (file)
index 0000000..f964861
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 1995-2005, Index Data ApS
+ * See the file LICENSE for details.
+ *
+ * $Id: mime.c,v 1.1 2006-03-15 13:32:05 adam Exp $
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <yaz/xmalloc.h>
+
+#include "mime.h"
+
+struct yaz_mime_entry {
+    char *suffix;
+    char *mime_type;
+    struct yaz_mime_entry *next;
+};
+
+struct yaz_mime_info {
+    struct yaz_mime_entry *table;
+};
+
+yaz_mime_types yaz_mime_types_create()
+{
+    yaz_mime_types p = xmalloc(sizeof(*p));
+    p->table = 0;
+    return p;
+}
+
+void yaz_mime_types_add(yaz_mime_types t, const char *suffix,
+                        const char *mime_type)
+{
+    struct yaz_mime_entry *e = xmalloc(sizeof(*e));
+    e->mime_type  = xstrdup(mime_type);
+    e->suffix = xstrdup(suffix);
+    e->next = t->table;
+    t->table = e;
+}
+
+const char *yaz_mime_lookup_suffix(yaz_mime_types t, const char *suffix)
+{
+    struct yaz_mime_entry *e = t->table;
+    for (; e; e = e->next)
+    {
+        if (!strcmp(e->suffix, suffix))
+            return e->mime_type;
+    }
+    return 0;
+}
+
+const char *yaz_mime_lookup_fname(yaz_mime_types t, const char *fname)
+{
+    const char *cp = strrchr(fname, '.');
+    if (!cp) /* if no . return now */
+        return 0;
+    return yaz_mime_lookup_suffix(t, cp+1);  /* skip . */
+}
+
+void yaz_mime_types_destroy(yaz_mime_types t)
+{
+    struct yaz_mime_entry *e = t->table;
+    while (e)
+    {
+        struct yaz_mime_entry *e_next = e->next;
+        xfree(e->suffix);
+        xfree(e->mime_type);
+        xfree(e);
+        e = e_next;
+    }
+    xfree(t);
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
diff --git a/src/mime.h b/src/mime.h
new file mode 100644 (file)
index 0000000..1ef5401
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 1995-2005, Index Data ApS
+ * See the file LICENSE for details.
+ *
+ * $Id: mime.h,v 1.1 2006-03-15 13:32:05 adam Exp $
+ */
+#ifndef MIME_H
+#define MIME_H
+
+typedef struct yaz_mime_info *yaz_mime_types;
+
+yaz_mime_types yaz_mime_types_create();
+void yaz_mime_types_add(yaz_mime_types t, const char *suffix,
+                        const char *mime_type);
+const char *yaz_mime_lookup_suffix(yaz_mime_types t, const char *suffix);
+const char *yaz_mime_lookup_fname(yaz_mime_types t, const char *fname);
+void yaz_mime_types_destroy(yaz_mime_types t);
+
+#endif
+
index 5a4f4ef..22df1a8 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1995-2005, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: seshigh.c,v 1.68 2006-03-13 11:59:27 adam Exp $
+ * $Id: seshigh.c,v 1.69 2006-03-15 13:32:05 adam Exp $
  */
 /**
  * \file seshigh.c
@@ -60,6 +60,7 @@
 #include <yaz/comstack.h>
 #include "eventl.h"
 #include "session.h"
+#include "mime.h"
 #include <yaz/proto.h>
 #include <yaz/oid.h>
 #include <yaz/log.h>
@@ -1383,6 +1384,32 @@ static void srw_bend_update(association *assoc, request *req,
     }
 }
 
+/* check if path is OK (1); BAD (0) */
+static int check_path(const char *path)
+{
+    if (*path != '/')
+        return 0;
+    if (strstr(path, ".."))
+        return 0;
+    return 1;
+}
+
+static char *read_file(const char *fname, ODR o, int *sz)
+{
+    char *buf;
+    FILE *inf = fopen(fname, "rb");
+    if (!inf)
+        return 0;
+
+    fseek(inf, 0L, SEEK_END);
+    *sz = ftell(inf);
+    rewind(inf);
+    buf = odr_malloc(o, *sz);
+    fread(buf, 1, *sz, inf);
+    fclose(inf);
+    return buf;     
+}
+
 static void process_http_request(association *assoc, request *req)
 {
     Z_HTTP_Request *hreq = req->gdu_request->u.HTTP_Request;
@@ -1394,7 +1421,7 @@ static void process_http_request(association *assoc, request *req)
     char *charset = 0;
     Z_HTTP_Response *hres = 0;
     int keepalive = 1;
-    char *stylesheet = 0;
+    const char *stylesheet = 0; /* for now .. set later */
     Z_SRW_diagnostic *diagnostic = 0;
     int num_diagnostic = 0;
     const char *host = z_HTTP_header_lookup(hreq->headers, "Host");
@@ -1404,14 +1431,63 @@ static void process_http_request(association *assoc, request *req)
         p = z_get_HTTP_Response(o, 404);
         r = 1;
     }
-    if (r == 2 && !strcmp(hreq->path, "/test")) 
+    if (r == 2 && assoc->docpath && hreq->path[0] == '/' 
+        && 
+        /* check if path is a proper prefix of documentroot */
+        strncmp(hreq->path+1, assoc->docpath, strlen(assoc->docpath))
+        == 0)
     {   
-        p = z_get_HTTP_Response(o, 200);
-        hres = p->u.HTTP_Response;
-        hres->content_buf = "1234567890\n";
-        hres->content_len = strlen(hres->content_buf);
+        if (!check_path(hreq->path))
+        {
+            yaz_log(YLOG_LOG, "File %s access forbidden", hreq->path+1);
+            p = z_get_HTTP_Response(o, 404);
+        }
+        else
+        {
+            int content_size = 0;
+            char *content_buf = read_file(hreq->path+1, o, &content_size);
+            if (!content_buf)
+            {
+                yaz_log(YLOG_LOG, "File %s not found", hreq->path+1);
+                p = z_get_HTTP_Response(o, 404);
+            }
+            else
+            {
+                const char *ctype = 0;
+                yaz_mime_types types = yaz_mime_types_create();
+                
+                yaz_mime_types_add(types, "xsl", "application/xml");
+                yaz_mime_types_add(types, "xml", "application/xml");
+                yaz_mime_types_add(types, "css", "text/css");
+                yaz_mime_types_add(types, "html", "text/html");
+                yaz_mime_types_add(types, "htm", "text/html");
+                yaz_mime_types_add(types, "txt", "text/plain");
+                
+                yaz_mime_types_add(types, "gif", "image/gif");
+                yaz_mime_types_add(types, "png", "image/png");
+                yaz_mime_types_add(types, "jpg", "image/jpeg");
+                yaz_mime_types_add(types, "jpeg", "image/jpeg");
+                
+                ctype = yaz_mime_lookup_fname(types, hreq->path);
+                if (!ctype)
+                {
+                    yaz_log(YLOG_LOG, "No mime type for %s", hreq->path+1);
+                    p = z_get_HTTP_Response(o, 404);
+                }
+                else
+                {
+                    p = z_get_HTTP_Response(o, 200);
+                    hres = p->u.HTTP_Response;
+                    hres->content_buf = content_buf;
+                    hres->content_len = content_size;
+                    z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
+                }
+                yaz_mime_types_destroy(types);
+            }
+        }
         r = 1;
     }
+
     if (r == 2)
     {
         r = yaz_srw_decode(hreq, &sr, &soap_package, assoc->decode, &charset);
@@ -1513,6 +1589,11 @@ static void process_http_request(association *assoc, request *req)
             int ret;
             p = z_get_HTTP_Response(o, 200);
             hres = p->u.HTTP_Response;
+
+            yaz_log(YLOG_LOG, "assoc->stylesheet=%s", assoc->stylesheet);
+            if (!stylesheet)
+                stylesheet = assoc->stylesheet;
+
             ret = z_soap_codec_enc_xsl(assoc->encode, &soap_package,
                                        &hres->content_buf, &hres->content_len,
                                        soap_handlers, charset, stylesheet);
@@ -1987,7 +2068,7 @@ static Z_APDU *process_initRequest(association *assoc, request *reqb)
                 assoc->init->implementation_name,
                 odr_prepend(assoc->encode, "GFS", resp->implementationName));
 
-    version = odr_strdup(assoc->encode, "$Revision: 1.68 $");
+    version = odr_strdup(assoc->encode, "$Revision: 1.69 $");
     if (strlen(version) > 10)   /* check for unexpanded CVS strings */
         version[strlen(version)-2] = '\0';
     resp->implementationVersion = odr_prepend(assoc->encode,
index f6070d1..b3f044a 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1995-2005, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: session.h,v 1.9 2005-06-25 15:46:05 adam Exp $
+ * $Id: session.h,v 1.10 2006-03-15 13:32:05 adam Exp $
  */
 /**
  * \file session.h
@@ -26,6 +26,8 @@ struct gfs_server {
     cql_transform_t cql_transform;
     void *server_node_ptr;
     char *directory;
+    char *docpath;
+    char *stylesheet;
     struct gfs_server *next;
 };
 
@@ -109,6 +111,8 @@ typedef struct association
     statserv_options_block *last_control;
     cql_transform_t cql_transform;
     void *server_node_ptr;
+    const char *docpath;
+    const char *stylesheet;
 } association;
 
 association *create_association(IOCHAN channel, COMSTACK link,
index f5aa6d1..c3d2e8b 100644 (file)
@@ -5,7 +5,7 @@
  * NT threaded server code by
  *   Chas Woodfield, Fretwell Downing Informatics.
  *
- * $Id: statserv.c,v 1.33 2005-10-20 19:28:04 quinn Exp $
+ * $Id: statserv.c,v 1.34 2006-03-15 13:32:05 adam Exp $
  */
 
 /**
@@ -219,6 +219,8 @@ static struct gfs_server * gfs_server_new()
     n->cql_transform = 0;
     n->server_node_ptr = 0;
     n->directory = 0;
+    n->docpath = 0;
+    n->stylesheet = 0;
     return n;
 }
 
@@ -262,6 +264,10 @@ int control_association(association *assoc, const char *host, int force_open)
             *cp = '\0';
         host = vhost;
     }
+    assoc->cql_transform = 0;
+    assoc->server_node_ptr = 0;
+    assoc->docpath = 0;
+    assoc->stylesheet = 0;
     if (control_block.xml_config[0])
     {
         struct gfs_server *gfs;
@@ -289,6 +295,8 @@ int control_association(association *assoc, const char *host, int force_open)
                     xfree(assoc->init);
                     assoc->init = 0;
                 }
+                assoc->docpath = gfs->docpath;
+                assoc->stylesheet = gfs->stylesheet;
                 assoc->cql_transform = gfs->cql_transform;
                 assoc->server_node_ptr = gfs->server_node_ptr;
                 assoc->last_control = &gfs->cb;
@@ -300,8 +308,6 @@ int control_association(association *assoc, const char *host, int force_open)
         }
         statserv_setcontrol(0);
         assoc->last_control = 0;
-        assoc->cql_transform = 0;
-        assoc->server_node_ptr = 0;
         yaz_log(YLOG_DEBUG, "server select: no match");
         return 0;
     }
@@ -309,8 +315,6 @@ int control_association(association *assoc, const char *host, int force_open)
     {
         statserv_setcontrol(&control_block);
         assoc->last_control = &control_block;
-        assoc->cql_transform = 0;
-        assoc->server_node_ptr = 0;
         yaz_log(YLOG_DEBUG, "server select: config=%s", control_block.configname);
         return 1;
     }
@@ -409,6 +413,28 @@ static void xml_config_read()
                     (*gfsp)->directory = 
                         nmem_dup_xml_content(gfs_nmem, ptr->children);
                 }
+                else if (!strcmp((const char *) ptr->name, "docpath"))
+                {
+                    (*gfsp)->docpath = 
+                        nmem_dup_xml_content(gfs_nmem, ptr->children);
+                }
+                else if (!strcmp((const char *) ptr->name, "stylesheet"))
+                {
+                    char *s = nmem_dup_xml_content(gfs_nmem, ptr->children);
+                    (*gfsp)->stylesheet = 
+                        nmem_malloc(gfs_nmem, strlen(s) + 2);
+                    sprintf((*gfsp)->stylesheet, "/%s", s);
+                }
+                else if (!strcmp((const char *) ptr->name, "explain"))
+                {
+                    ; /* being processed separately */
+                }
+                else
+                {
+                    yaz_log(YLOG_FATAL, "Unknown element '%s' in config %s",
+                            ptr->name, control_block.xml_config);
+                    exit(1);
+                }
             }
             gfsp = &(*gfsp)->next;
         }
index da5d56f..4cac3a4 100644 (file)
@@ -1,6 +1,6 @@
 # Copyright (C) 1994-2005, Index Data ApS
 # All rights reserved.
-# $Id: makefile,v 1.101 2006-03-14 08:50:19 adam Exp $
+# $Id: makefile,v 1.102 2006-03-15 13:32:06 adam Exp $
 #
 # Programmed by
 #  Heikki Levanto & Adam Dickmeiss
@@ -399,7 +399,8 @@ YAZ_ZUTIL_OBJS= \
    $(OBJDIR)\zoom-c.obj \
    $(OBJDIR)\zoom-opt.obj \
    $(OBJDIR)\initopt.obj \
-   $(OBJDIR)\xmlquery.obj
+   $(OBJDIR)\xmlquery.obj \
+   $(OBJDIR)\mime.obj
 
 Z3950_OBJS= \
    $(OBJDIR)\z-date.obj\