From a6af2d19dddb0c2ef961d087d8ca0f2b3bda8f7a Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Wed, 15 Mar 2006 13:32:05 +0000 Subject: [PATCH] Added support for file access in GFS to facilitate static web pages, such XSL/CSS/HTML files. --- doc/gfs-virtual.xml | 26 +++++++++++++- etc/yazgfs.xml | 6 ++-- src/Makefile.am | 5 +-- src/mime.c | 83 +++++++++++++++++++++++++++++++++++++++++++ src/mime.h | 20 +++++++++++ src/seshigh.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++----- src/session.h | 6 +++- src/statserv.c | 36 ++++++++++++++++--- win/makefile | 5 +-- 9 files changed, 263 insertions(+), 21 deletions(-) create mode 100644 src/mime.c create mode 100644 src/mime.h diff --git a/doc/gfs-virtual.xml b/doc/gfs-virtual.xml index 340b641..62e8a0b 100644 --- a/doc/gfs-virtual.xml +++ b/doc/gfs-virtual.xml @@ -1,5 +1,5 @@ @@ -134,6 +134,30 @@ + + element stylesheet (optional) + + + 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. + + + + + element docpath (optional) + + + 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 xsl, the docpath would be + xsl and all URLs of the form + http://host/exl will result in a local file access. + + + element explain (optional) diff --git a/etc/yazgfs.xml b/etc/yazgfs.xml index 8dbc21a..72f1272 100644 --- a/etc/yazgfs.xml +++ b/etc/yazgfs.xml @@ -1,12 +1,14 @@ - + tcp:@:9000 - + . zebra.cfg pqf.properties + xsl + xsl/default.xsl myserver.org diff --git a/src/Makefile.am b/src/Makefile.am index 88c71cb..090f5ff 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 index 0000000..f964861 --- /dev/null +++ b/src/mime.c @@ -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 +#include +#include +#include + +#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 index 0000000..1ef5401 --- /dev/null +++ b/src/mime.h @@ -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 + diff --git a/src/seshigh.c b/src/seshigh.c index 5a4f4ef..22df1a8 100644 --- a/src/seshigh.c +++ b/src/seshigh.c @@ -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 #include "eventl.h" #include "session.h" +#include "mime.h" #include #include #include @@ -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, diff --git a/src/session.h b/src/session.h index f6070d1..b3f044a 100644 --- a/src/session.h +++ b/src/session.h @@ -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, diff --git a/src/statserv.c b/src/statserv.c index f5aa6d1..c3d2e8b 100644 --- a/src/statserv.c +++ b/src/statserv.c @@ -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; } diff --git a/win/makefile b/win/makefile index da5d56f..4cac3a4 100644 --- a/win/makefile +++ b/win/makefile @@ -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\ -- 1.7.10.4