xslt.c 3.94 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

Karl Heyes's avatar
Karl Heyes committed
23 24 25 26
#include "thread/thread.h"
#include "avl/avl.h"
#include "httpp/httpp.h"
#include "net/sock.h"
27 28 29 30 31 32 33 34

#include "connection.h"

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

35
#define CATMODULE "xslt"
Karl Heyes's avatar
Karl Heyes committed
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
#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
{
    xmlOutputBufferPtr outputBuffer;
137 138 139
    xmlDocPtr    res;
    xsltStylesheetPtr cur;
    const char *params[16 + 1];
140
    size_t count,bytes;
141

142
    params[0] = NULL;
143

144 145
    xmlSubstituteEntitiesDefault(1);
    xmlLoadExtDtdDefaultValue = 1;
146

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

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

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