#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef _WIN32 #include #endif #include #include #include #include #include "connection.h" #include "global.h" #include "refbuf.h" #include "client.h" #include "stats.h" #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) { #ifdef _WIN32 if(!stricmp(fn, cache[i].filename)) #else if(!strcmp(fn, cache[i].filename)) #endif { 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); } DEBUG1("Using cached sheet %i", i); 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; } void xslt_transform(xmlDocPtr doc, char *xslfilename, client_t *client) { xmlOutputBufferPtr outputBuffer; xmlDocPtr res; xsltStylesheetPtr cur; const char *params[16 + 1]; size_t count,bytes; params[0] = NULL; xmlSubstituteEntitiesDefault(1); xmlLoadExtDtdDefaultValue = 1; thread_mutex_lock(&xsltlock); cur = xslt_get_stylesheet(xslfilename); thread_mutex_unlock(&xsltlock); if (cur == NULL) { bytes = sock_write_string(client->con->sock, (char *)"Could not parse XSLT file"); if(bytes > 0) client->con->sent_bytes += bytes; return; } res = xsltApplyStylesheet(cur, doc, params); outputBuffer = xmlAllocOutputBuffer(NULL); count = xsltSaveResultTo(outputBuffer, res, cur); /* Add null byte to end. */ bytes = xmlOutputBufferWrite(outputBuffer, 1, ""); if(sock_write_string(client->con->sock, (char *)outputBuffer->buffer->content)) client->con->sent_bytes += bytes; xmlOutputBufferClose(outputBuffer); xmlFreeDoc(res); }