xslt.c 3.85 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
#include <string.h>
#include <libxml/xmlmemory.h>
#include <libxml/debugXML.h>
#include <libxml/HTMLtree.h>
#include <libxml/xmlIO.h>
#include <libxml/DOCBparser.h>
#include <libxml/xinclude.h>
#include <libxml/catalog.h>
#include <libxslt/xslt.h>
#include <libxslt/xsltInternals.h>
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>

14 15 16 17 18 19 20 21
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>

#ifndef _WIN32
#include <sys/time.h>
#endif

22 23 24 25 26 27 28 29 30 31 32 33 34

#include <thread/thread.h>
#include <avl/avl.h>
#include <httpp/httpp.h>
#include <net/sock.h>

#include "connection.h"

#include "global.h"
#include "refbuf.h"
#include "client.h"
#include "stats.h"

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
#define CATMODULE "xslt"
#include "log.h"
#include "logging.h"

typedef struct {
    char              *filename;
    time_t             last_modified;
    time_t             cache_age;
    xsltStylesheetPtr  stylesheet;
} stylesheet_cache_t;

/* Keep it small... */
#define CACHESIZE 3

stylesheet_cache_t cache[CACHESIZE];
mutex_t xsltlock;

void xslt_initialize()
{
    memset(cache, 0, sizeof(stylesheet_cache_t)*CACHESIZE);
    thread_mutex_create(&xsltlock);
}

void xslt_shutdown() {
    int i;

    for(i=0; i < CACHESIZE; i++) {
        if(cache[i].filename)
            free(cache[i].filename);
        if(cache[i].stylesheet)
            xsltFreeStylesheet(cache[i].stylesheet);
    }

    xsltCleanupGlobals();
}

static int evict_cache_entry() {
    int i, age=0, oldest;

    for(i=0; i < CACHESIZE; i++) {
        if(cache[i].cache_age > age) {
            age = cache[i].cache_age;
            oldest = i;
        }
    }

    xsltFreeStylesheet(cache[oldest].stylesheet);
    free(cache[oldest].filename);

    return oldest;
}

static xsltStylesheetPtr xslt_get_stylesheet(char *fn) {
    int i;
    int empty = -1;
    struct stat file;

    if(stat(fn, &file)) {
        DEBUG1("Error checking for stylesheet file: %s", strerror(errno));
        return NULL;
    }

    for(i=0; i < CACHESIZE; i++) {
        if(cache[i].filename)
        {
100 101 102
#ifdef _WIN32
            if(!stricmp(fn, cache[i].filename))
#else
103
            if(!strcmp(fn, cache[i].filename))
104
#endif
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
            {
                if(file.st_mtime > cache[i].last_modified)
                {
                    xsltFreeStylesheet(cache[i].stylesheet);

                    cache[i].last_modified = file.st_mtime;
                    cache[i].stylesheet = xsltParseStylesheetFile(fn);
                    cache[i].cache_age = time(NULL);
                }
                return cache[i].stylesheet;
            }
        }
        else
            empty = i;
    }

    if(empty>=0)
        i = empty;
    else
        i = evict_cache_entry();

    cache[i].last_modified = file.st_mtime;
    cache[i].filename = strdup(fn);
    cache[i].stylesheet = xsltParseStylesheetFile(fn);
    cache[i].cache_age = time(NULL);
    return cache[i].stylesheet;
}
132

133
void xslt_transform(xmlDocPtr doc, char *xslfilename, client_t *client)
134 135 136 137 138
{
    xmlOutputBufferPtr outputBuffer;
	xmlDocPtr	res;
	xsltStylesheetPtr cur;
	const char *params[16 + 1];
139
    size_t count,bytes;
140 141 142 143 144 145

	params[0] = NULL;

	xmlSubstituteEntitiesDefault(1);
	xmlLoadExtDtdDefaultValue = 1;

146 147 148 149
    thread_mutex_lock(&xsltlock);
    cur = xslt_get_stylesheet(xslfilename);
    thread_mutex_unlock(&xsltlock);

150
	if (cur == NULL) {
151 152 153 154
		bytes = sock_write_string(client->con->sock, 
                (char *)"Could not parse XSLT file");
        if(bytes > 0) client->con->sent_bytes += bytes;
        
155 156 157 158 159 160 161 162 163 164
        return;
	}

    res = xsltApplyStylesheet(cur, doc, params);

    outputBuffer = xmlAllocOutputBuffer(NULL);

    count = xsltSaveResultTo(outputBuffer, res, cur);

    /*  Add null byte to end. */
165
    bytes = xmlOutputBufferWrite(outputBuffer, 1, "");
166

167 168 169 170
	if(sock_write_string(client->con->sock, 
                (char *)outputBuffer->buffer->content))
        client->con->sent_bytes += bytes;
    
171 172 173 174 175

    xmlFree(outputBuffer);
    xmlFreeDoc(res);
}