xslt.c 3.92 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
            {
                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);
                }
114
                DEBUG1("Using cached sheet %i", i);
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
                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;
}
133

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

	params[0] = NULL;

	xmlSubstituteEntitiesDefault(1);
	xmlLoadExtDtdDefaultValue = 1;

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

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

    res = xsltApplyStylesheet(cur, doc, params);

    outputBuffer = xmlAllocOutputBuffer(NULL);

    count = xsltSaveResultTo(outputBuffer, res, cur);

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

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