[open-ils-commits] r14660 - in trunk/Open-ILS: examples/apache src/apachemods (miker)
svn at svn.open-ils.org
svn at svn.open-ils.org
Wed Oct 28 21:00:28 EDT 2009
Author: miker
Date: 2009-10-28 21:00:26 -0400 (Wed, 28 Oct 2009)
New Revision: 14660
Added:
trunk/Open-ILS/src/apachemods/mod_idlchunk.c
Modified:
trunk/Open-ILS/examples/apache/eg_vhost.conf
trunk/Open-ILS/src/apachemods/Makefile.am
Log:
adding specialized apache module for returning specific classes from the IDL xml
Modified: trunk/Open-ILS/examples/apache/eg_vhost.conf
===================================================================
--- trunk/Open-ILS/examples/apache/eg_vhost.conf 2009-10-28 21:52:02 UTC (rev 14659)
+++ trunk/Open-ILS/examples/apache/eg_vhost.conf 2009-10-29 01:00:26 UTC (rev 14660)
@@ -321,12 +321,14 @@
Options +Includes
AddOutputFilter INCLUDES;XMLENT .xhtml
</LocationMatch>
+
<LocationMatch /reports/fm_IDL.xml>
- Options +Includes
- XMLEntStripDoctype "yes"
- XMLEntStripComments "no"
- XMLEntContentType "text/xml; charset=utf-8"
- AddOutputFilter INCLUDES;XMLENT .xml
+ IDLChunkStripPI "yes"
+ IDLChunkEscapeScript "no"
+ IDLChunkStripComments "yes"
+ IDLChunkStripDoctype "yes"
+ IDLChunkContentType "application/xml; charset=utf-8"
+ AddOutputFilter IDLCHUNK .xml
</LocationMatch>
# ----------------------------------------------------------------------------------
Modified: trunk/Open-ILS/src/apachemods/Makefile.am
===================================================================
--- trunk/Open-ILS/src/apachemods/Makefile.am 2009-10-28 21:52:02 UTC (rev 14659)
+++ trunk/Open-ILS/src/apachemods/Makefile.am 2009-10-29 01:00:26 UTC (rev 14660)
@@ -16,6 +16,9 @@
apachemods:
$(APXS2) -c $(AM_LDFLAGS) -lxml2 -lopensrf -lxslt -lexpat $(AM_CFLAGS) @srcdir@/mod_xmlent.c
$(APXS2) -i -a @srcdir@/mod_xmlent.la
+ $(APXS2) -c $(AM_LDFLAGS) -lxml2 -lopensrf -lxslt -lexpat $(AM_CFLAGS) @srcdir@/mod_idlchunk.c
+ $(APXS2) -i -a @srcdir@/mod_idlchunk.la
clean-local:
rm -f @srcdir@/mod_xmlent.la @srcdir@/mod_xmlent.lo @srcdir@/mod_xmlent.slo
+ rm -f @srcdir@/mod_idlchunk.la @srcdir@/mod_idlchunk.lo @srcdir@/mod_idlchunk.slo
Added: trunk/Open-ILS/src/apachemods/mod_idlchunk.c
===================================================================
--- trunk/Open-ILS/src/apachemods/mod_idlchunk.c (rev 0)
+++ trunk/Open-ILS/src/apachemods/mod_idlchunk.c 2009-10-29 01:00:26 UTC (rev 14660)
@@ -0,0 +1,637 @@
+#include "httpd.h"
+/* vim:noet:ts=4
+ */
+#include "http_config.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_request.h"
+//#include "apr_compat.h"
+#include "apr_strings.h"
+#include "apr_reslist.h"
+#include "http_log.h"
+#include "util_filter.h"
+#include "opensrf/string_array.h"
+#include "opensrf/utils.h"
+#include "opensrf/log.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <expat.h>
+
+#define APACHE_TOOLS_MAX_POST_SIZE 10485760 /* 10 MB */
+#define MODULE_NAME "idlchunk_module"
+
+/* Define the config defaults here */
+#define MODIDLCHUNK_CONFIG_STRIP_COMMENTS "IDLChunkStripComments"
+#define MODIDLCHUNK_CONFIG_CONTENT_TYPE "IDLChunkContentType"
+#define MODIDLCHUNK_CONFIG_CONTENT_TYPE_DEFAULT "text/html"
+#define MODIDLCHUNK_CONFIG_STRIP_PI "IDLChunkStripPI"
+#define MODIDLCHUNK_CONFIG_DOCTYPE "IDLChunkDoctype"
+#define MODIDLCHUNK_CONFIG_STRIP_DOCTYPE "IDLChunkStripDoctype"
+#define MODIDLCHUNK_CONFIG_ESCAPE_SCRIPT "IDLChunkEscapeScript"
+
+module AP_MODULE_DECLARE_DATA idlchunk_module;
+
+int idlChunkInScript = 0; /* are we in the middle of a <script> tag */
+osrfStringArray* mparams = NULL;
+
+int inChunk = 0;
+int all = 0;
+
+/* our context */
+typedef struct {
+ apr_bucket_brigade* brigade; /* the bucket brigade we buffer our data into */
+ XML_Parser parser; /* our XML parser */
+} idlChunkContext;
+
+/* our config data */
+typedef struct {
+ int stripComments; /* should we strip comments on the way out? */
+ int stripPI; /* should we strip processing instructions on the way out? */
+ int stripDoctype;
+ int escapeScript; /* if true, we html-escape anything text inside a <script> tag */
+ char* contentType; /* the content type used to server pages */
+ char* doctype; /* the doctype header to send before any other data */
+} idlChunkConfig;
+
+
+static osrfStringArray* apacheParseParms(request_rec* r) {
+
+ if( r == NULL ) return NULL;
+ //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "got a valid request_rec");
+
+ char* arg = NULL;
+ apr_pool_t *p = r->pool; /* memory pool */
+ growing_buffer* buffer = buffer_init(1025);
+
+ /* gather the post args and append them to the url query string */
+ if( !strcmp(r->method,"POST") ) {
+
+ ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK);
+
+ //osrfLogDebug(OSRF_LOG_MARK, "gateway reading post data..");
+ //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "idlchunk reading post data..");
+
+ if(ap_should_client_block(r)) {
+
+
+ /* Start with url query string, if any */
+
+ if(r->args && r->args[0])
+ buffer_add(buffer, r->args);
+
+ char body[1025];
+
+ //osrfLogDebug(OSRF_LOG_MARK, "gateway client has post data, reading...");
+
+ /* Append POST data */
+
+ long bread;
+ while( (bread = ap_get_client_block(r, body, sizeof(body) - 1)) ) {
+
+ if(bread < 0) {
+ //osrfLogInfo(OSRF_LOG_MARK,
+ // "ap_get_client_block(): returned error, exiting POST reader");
+ break;
+ }
+
+ body[bread] = '\0';
+ buffer_add( buffer, body );
+
+ //osrfLogDebug(OSRF_LOG_MARK,
+ // "gateway read %ld bytes: %d bytes of data so far", bread, buffer->n_used);
+
+ if(buffer->n_used > APACHE_TOOLS_MAX_POST_SIZE) {
+ //osrfLogError(OSRF_LOG_MARK, "gateway received POST larger "
+ // "than %d bytes. dropping request", APACHE_TOOLS_MAX_POST_SIZE);
+ buffer_free(buffer);
+ return NULL;
+ }
+ }
+
+ //osrfLogDebug(OSRF_LOG_MARK, "gateway done reading post data");
+ }
+
+ } else { /* GET */
+
+ if(r->args && r->args[0])
+ buffer_add(buffer, r->args);
+ //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "idlchunk read GET data..");
+ }
+
+
+ if(buffer->n_used > 0)
+ arg = apr_pstrdup(p, buffer->buf);
+ else
+ arg = NULL;
+ buffer_free(buffer);
+
+ if( !arg || !arg[0] ) { /* we received no request */
+ return NULL;
+ }
+
+ //osrfLogDebug(OSRF_LOG_MARK, "parsing URL params from post/get request data: %s", arg);
+ //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "parsing URL params from post/get request data: %s", arg);
+
+ osrfStringArray* sarray = osrfNewStringArray(12); /* method parameters */
+ int sanity = 0;
+ char* key = NULL; /* query item name */
+ char* val = NULL; /* query item value */
+
+ /* Parse the post/get request data into a series of name/value pairs. */
+ /* Load each name into an even-numbered slot of an osrfStringArray, and */
+ /* the corresponding value into the following odd-numbered slot. */
+
+ while( arg && (val = ap_getword(p, (const char**) &arg, '&'))) {
+
+ key = ap_getword(r->pool, (const char**) &val, '=');
+ if(!key || !key[0])
+ break;
+
+ ap_unescape_url(key);
+ ap_unescape_url(val);
+
+ //osrfLogDebug(OSRF_LOG_MARK, "parsed URL params %s=%s", key, val);
+
+ osrfStringArrayAdd(sarray, key);
+ osrfStringArrayAdd(sarray, val);
+
+ if( sanity++ > 1000 ) {
+ //osrfLogError(OSRF_LOG_MARK,
+ // "Parsing URL params failed sanity check: 1000 iterations");
+ osrfStringArrayFree(sarray);
+ return NULL;
+ }
+
+ }
+
+ //osrfLogDebug(OSRF_LOG_MARK,
+ // "Apache tools parsed %d params key/values", sarray->size / 2 );
+
+ return sarray;
+}
+
+
+
+static osrfStringArray* apacheGetParamKeys(osrfStringArray* params) {
+ if(params == NULL) return NULL;
+ osrfStringArray* sarray = osrfNewStringArray(12);
+ int i;
+ //osrfLogDebug(OSRF_LOG_MARK, "Fetching URL param keys");
+ for( i = 0; i < params->size; i++ )
+ osrfStringArrayAdd(sarray, osrfStringArrayGetString(params, i++));
+ return sarray;
+}
+
+static osrfStringArray* apacheGetParamValues(osrfStringArray* params, char* key) {
+
+ if(params == NULL || key == NULL) return NULL;
+ osrfStringArray* sarray = osrfNewStringArray(12);
+
+ //osrfLogDebug(OSRF_LOG_MARK, "Fetching URL values for key %s", key);
+ int i;
+ for( i = 0; i < params->size; i++ ) {
+ const char* nkey = osrfStringArrayGetString(params, i++);
+ if(nkey && !strcmp(nkey, key))
+ osrfStringArrayAdd(sarray, osrfStringArrayGetString(params, i));
+ }
+ return sarray;
+}
+
+
+static char* apacheGetFirstParamValue(osrfStringArray* params, char* key) {
+ if(params == NULL || key == NULL) return NULL;
+
+ int i;
+ //osrfLogDebug(OSRF_LOG_MARK, "Fetching first URL value for key %s", key);
+ for( i = 0; i < params->size; i++ ) {
+ const char* nkey = osrfStringArrayGetString(params, i++);
+ if(nkey && !strcmp(nkey, key))
+ return strdup(osrfStringArrayGetString(params, i));
+ }
+
+ return NULL;
+}
+
+
+static int apacheDebug( char* msg, ... ) {
+ VA_LIST_TO_STRING(msg);
+ fprintf(stderr, "%s\n", VA_BUF);
+ fflush(stderr);
+ return 0;
+}
+
+
+static int apacheError( char* msg, ... ) {
+ VA_LIST_TO_STRING(msg);
+ fprintf(stderr, "%s\n", VA_BUF);
+ fflush(stderr);
+ return HTTP_INTERNAL_SERVER_ERROR;
+}
+
+
+
+
+/* get the content type from the config */
+static const char* idlChunkSetContentType(cmd_parms *params, void *cfg, const char *arg) {
+ idlChunkConfig* config = (idlChunkConfig*) cfg;
+ config->contentType = (char*) arg;
+ return NULL;
+}
+
+
+/* get the strip PI flag from the config */
+static const char* idlChunkSetStripPI(cmd_parms *params, void *cfg, const char *arg) {
+ idlChunkConfig* config = (idlChunkConfig*) cfg;
+ char* a = (char*) arg;
+ config->stripPI = (a && !strcasecmp(a, "yes")) ? 1 : 0;
+ return NULL;
+}
+
+/* Get the strip comments flag from the config */
+static const char* idlChunkSetStripComments(cmd_parms *params, void *cfg, const char *arg) {
+ idlChunkConfig* config = (idlChunkConfig*) cfg;
+ char* a = (char*) arg;
+ config->stripComments = (a && !strcasecmp(a, "yes")) ? 1 : 0;
+ return NULL;
+}
+
+static const char* idlChunkSetEscapeScript(cmd_parms *params, void *cfg, const char *arg) {
+ idlChunkConfig* config = (idlChunkConfig*) cfg;
+ char* a = (char*) arg;
+ config->escapeScript = (a && !strcasecmp(a, "yes")) ? 1 : 0;
+ return NULL;
+}
+
+static const char* idlChunkSetStripDoctype(cmd_parms *params, void *cfg, const char *arg) {
+ idlChunkConfig* config = (idlChunkConfig*) cfg;
+ char* a = (char*) arg;
+ config->stripDoctype = (a && !strcasecmp(a, "yes")) ? 1 : 0;
+ return NULL;
+}
+
+
+/* Get the user defined doctype from the config */
+static const char* idlChunkSetDoctype(cmd_parms *params, void *cfg, const char *arg) {
+ idlChunkConfig* config = (idlChunkConfig*) cfg;
+ config->doctype = (char*) arg;
+ return NULL;
+}
+
+/* Tell apache how to set our config variables */
+static const command_rec idlChunkCommands[] = {
+ AP_INIT_TAKE1( MODIDLCHUNK_CONFIG_STRIP_COMMENTS,
+ idlChunkSetStripComments, NULL, ACCESS_CONF, "IDLCHUNK Strip Comments"),
+ AP_INIT_TAKE1( MODIDLCHUNK_CONFIG_CONTENT_TYPE,
+ idlChunkSetContentType, NULL, ACCESS_CONF, "IDLCHUNK Content Type"),
+ AP_INIT_TAKE1( MODIDLCHUNK_CONFIG_STRIP_PI,
+ idlChunkSetStripPI, NULL, ACCESS_CONF, "IDLCHUNK Strip XML Processing Instructions"),
+ AP_INIT_TAKE1( MODIDLCHUNK_CONFIG_DOCTYPE,
+ idlChunkSetDoctype, NULL, ACCESS_CONF, "IDLCHUNK Doctype Declaration"),
+ AP_INIT_TAKE1( MODIDLCHUNK_CONFIG_STRIP_DOCTYPE,
+ idlChunkSetStripDoctype, NULL, ACCESS_CONF, "IDLCHUNK Strip Doctype Declaration"),
+ AP_INIT_TAKE1( MODIDLCHUNK_CONFIG_ESCAPE_SCRIPT,
+ idlChunkSetEscapeScript, NULL, ACCESS_CONF, "IDLCHUNK Escape data in script tags"),
+ {NULL}
+};
+
+/* Creates a new config object */
+static void* idlChunkCreateDirConfig( apr_pool_t* p, char* dir ) {
+ idlChunkConfig* config =
+ (idlChunkConfig*) apr_palloc( p, sizeof(idlChunkConfig) );
+
+ config->stripComments = 0;
+ config->stripPI = 0;
+ config->stripDoctype = 1;
+ config->escapeScript = 1;
+ config->contentType = MODIDLCHUNK_CONFIG_CONTENT_TYPE_DEFAULT;
+ config->doctype = NULL;
+
+ return (void*) config;
+}
+
+/* keep for a while in case we ever need it */
+/*
+#define IDLCHUNK_INHERIT(p, c, f) ((c->f) ? c->f : p->f);
+static void* idlChunkMergeDirConfig(apr_pool_t *p, void *base, void *overrides) {
+ idlChunkConfig* parent = base;
+ idlChunkConfig* child = overrides;
+ idlChunkConfig* newConf = (idlChunkConfig*) apr_pcalloc(p, sizeof(idlChunkConfig));
+ newConf->contentType = IDLCHUNK_INHERIT(parent, child, contentType);
+ newConf->stripComments = IDLCHUNK_INHERIT(parent, child, stripComments);
+ return newConf;
+}
+*/
+
+
+/* We need a global parser object because sub-requests, with different
+ * filter contexts, are parsing part of the same document.
+ * This means that this filter will only work in forked (non-threaded) environments.
+ * XXX Figure out how to share pointers/data accross filters */
+XML_Parser parser = NULL;
+
+/* utility function which passes data to the next filter */
+static void _fwrite( ap_filter_t* filter, char* data, ... ) {
+ if(!(filter && data)) return;
+ idlChunkContext* ctx = (idlChunkContext*) filter->ctx;
+ VA_LIST_TO_STRING(data);
+ ap_fwrite( filter->next, ctx->brigade, VA_BUF, strlen(VA_BUF));
+}
+
+
+/** XXX move me to opensrf/utils.h */
+#define OSRF_UTILS_REPLACE_CHAR(str, o, n)\
+ do {\
+ int i = 0;\
+ while(str[i] != '\0') {\
+ if(str[i] == o)\
+ str[i] = n;\
+ i++;\
+ }\
+ } while(0)
+
+/* cycles through the attributes attached to an element */
+static char* find_id_attr( const char** atts ) {
+ if(!atts) return NULL;
+ int i;
+ for( i = 0; atts[i] && atts[i+1]; i++ ) {
+ const char* name = atts[i];
+ char* value = (char*)atts[i+1];
+ if (!strcmp(name,"id")) return value;
+ i++;
+ }
+}
+
+/* cycles through the attributes attached to an element */
+static void printAttr( ap_filter_t* filter, const char** atts ) {
+ if(!atts) return;
+ int i;
+ for( i = 0; atts[i] && atts[i+1]; i++ ) {
+ const char* name = atts[i];
+ const char* value = atts[i+1];
+ char* escaped = ap_escape_html(filter->r->pool, value);
+
+ /* we make a big assumption here that if the string contains a ',
+ * then the original attribute was wrapped in "s - so recreate that */
+ if( strchr( escaped, '\'' ) ) {
+ OSRF_UTILS_REPLACE_CHAR(escaped,'"','\'');
+ _fwrite( filter, " %s=\"%s\"", name, escaped );
+
+ } else {
+ OSRF_UTILS_REPLACE_CHAR(escaped,'\'','"');
+ _fwrite( filter, " %s='%s'", name, escaped );
+ }
+
+ i++;
+ }
+}
+
+/* Starts an XML element */
+static void XMLCALL startElement(void *userData, const char *name, const char **atts) {
+
+ ap_filter_t* filter = (ap_filter_t*) userData;
+
+
+ if (!strcmp(name,"class")) {
+ //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, filter->r,"Looking at %s with id of %s",name, find_id_attr(atts));
+
+ if (osrfStringArrayContains(mparams, find_id_attr(atts))) {
+ inChunk = 1;
+ //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, filter->r,"Found desired class %s", find_id_attr(atts));
+ }
+ }
+
+ if (all || inChunk || (name && (!strcmp(name,"IDL")))) {
+
+ idlChunkConfig* config = ap_get_module_config(
+ filter->r->per_dir_config, &idlchunk_module );
+ _fwrite(filter, "<%s", name );
+ printAttr( filter, atts );
+ if (!strncmp(config->contentType, MODIDLCHUNK_CONFIG_CONTENT_TYPE_DEFAULT, 9)) {
+ _fwrite(filter, " />", name );
+ } else {
+ _fwrite(filter, ">", name );
+ }
+ if(!strcmp(name, "script"))
+ idlChunkInScript = 1;
+ }
+}
+
+/* Handles the character data */
+static void XMLCALL charHandler( void* userData, const XML_Char* s, int len ) {
+ ap_filter_t* filter = (ap_filter_t*) userData;
+ char data[len+1];
+ memset( data, '\0', sizeof(data) );
+ memcpy( data, s, len );
+
+ idlChunkConfig* config = ap_get_module_config(
+ filter->r->per_dir_config, &idlchunk_module );
+
+ if (all || inChunk) {
+ if( idlChunkInScript && ! config->escapeScript ) {
+ _fwrite( filter, "%s", data );
+
+ } else {
+ char* escaped = ap_escape_html(filter->r->pool, data);
+ _fwrite( filter, "%s", escaped );
+ }
+ }
+}
+
+static void XMLCALL handlePI( void* userData, const XML_Char* target, const XML_Char* data) {
+ ap_filter_t* filter = (ap_filter_t*) userData;
+ _fwrite(filter, "<?%s %s?>", target, data);
+}
+
+static void XMLCALL handleComment( void* userData, const XML_Char* comment ) {
+ ap_filter_t* filter = (ap_filter_t*) userData;
+ _fwrite(filter, "<!-- %s -->", comment);
+}
+
+/* Ends an XML element */
+static void XMLCALL endElement(void *userData, const char *name) {
+
+ if (all || inChunk || (name && (!strcmp(name,"IDL")))) {
+
+ ap_filter_t* filter = (ap_filter_t*) userData;
+ idlChunkConfig* config = ap_get_module_config(
+ filter->r->per_dir_config, &idlchunk_module );
+ if (!strncmp(config->contentType, MODIDLCHUNK_CONFIG_CONTENT_TYPE_DEFAULT, 9)) {
+ return;
+ }
+ _fwrite( filter, "</%s>", name );
+ if(!strcmp(name, "script"))
+ idlChunkInScript = 1;
+
+ }
+ if (!strcmp(name,"class")) inChunk = 0;
+}
+
+static void XMLCALL doctypeHandler( void* userData,
+ const char* name, const char* sysid, const char* pubid, int hasinternal ) {
+
+ ap_filter_t* filter = (ap_filter_t*) userData;
+ char* s = (sysid) ? (char*) sysid : "";
+ char* p = (pubid) ? (char*) pubid : "";
+ _fwrite( filter, "<!DOCTYPE %s PUBLIC \"%s\" \"%s\">\n", name, p, s );
+}
+
+
+/* The handler. Create a new parser and/or filter context where appropriate
+ * and parse the chunks of data received from the brigade
+ */
+static int idlChunkHandler( ap_filter_t *f, apr_bucket_brigade *brigade ) {
+
+ idlChunkContext* ctx = f->ctx;
+ apr_bucket* currentBucket = NULL;
+ apr_pool_t* pool = f->r->pool;
+ const char* data;
+ apr_size_t len;
+ osrfStringArray* params = NULL;
+ mparams = NULL;
+
+ /* load the per-dir/location config */
+ idlChunkConfig* config = ap_get_module_config(
+ f->r->per_dir_config, &idlchunk_module );
+
+ ap_log_rerror(APLOG_MARK, APLOG_ERR,
+ 0, f->r, "IDLCHUNK Config:\nContent Type = %s, "
+ "Strip PI = %s, Strip Comments = %s, Doctype = %s",
+ config->contentType,
+ (config->stripPI) ? "yes" : "no",
+ (config->stripComments) ? "yes" : "no",
+ config->doctype);
+
+ /* set the content type based on the config */
+ ap_set_content_type(f->r, config->contentType);
+
+ //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, "Set content type");
+
+ params = apacheParseParms(f->r); /* free me */
+ mparams = apacheGetParamValues( params, "class" ); /* free me */
+
+ all = 1;
+
+ if (mparams && mparams->size > 0) all = 0;
+
+ //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, "Parsed the params, if any");
+
+ /* create the XML parser */
+ int firstrun = 0;
+ if( parser == NULL ) {
+ firstrun = 1;
+ parser = XML_ParserCreate("UTF-8");
+ XML_SetUserData(parser, f);
+ XML_SetElementHandler(parser, startElement, endElement);
+ XML_SetCharacterDataHandler(parser, charHandler);
+ if(!config->stripDoctype)
+ XML_SetStartDoctypeDeclHandler( parser, doctypeHandler );
+ if(!config->stripPI)
+ XML_SetProcessingInstructionHandler(parser, handlePI);
+ if(!config->stripComments)
+ XML_SetCommentHandler(parser, handleComment);
+ }
+
+ /* create the filter context */
+ if( ctx == NULL ) {
+ f->ctx = ctx = apr_pcalloc( pool, sizeof(*ctx));
+ ctx->brigade = apr_brigade_create( pool, f->c->bucket_alloc );
+ ctx->parser = parser;
+ }
+
+
+ if(firstrun) { /* we haven't started writing the data to the stream yet */
+
+ /* go ahead and write the doctype out if we have one defined */
+ if(config->doctype) {
+ ap_log_rerror( APLOG_MARK, APLOG_DEBUG,
+ 0, f->r, "IDLCHUNK DOCTYPE => %s", config->doctype);
+ _fwrite(f, "%s\n", config->doctype);
+ }
+ }
+
+
+ /* cycle through the buckets in the brigade */
+ while (!APR_BRIGADE_EMPTY(brigade)) {
+
+ /* grab the next bucket */
+ currentBucket = APR_BRIGADE_FIRST(brigade);
+
+ /* clean up when we're done */
+ if (APR_BUCKET_IS_EOS(currentBucket) || APR_BUCKET_IS_FLUSH(currentBucket)) {
+ APR_BUCKET_REMOVE(currentBucket);
+ APR_BRIGADE_INSERT_TAIL(ctx->brigade, currentBucket);
+ ap_pass_brigade(f->next, ctx->brigade);
+ XML_ParserFree(parser);
+ if (params) osrfStringArrayFree(params);
+ if (mparams) osrfStringArrayFree(mparams);
+ parser = NULL;
+ return APR_SUCCESS;
+ }
+
+ /* read the incoming data */
+ int s = apr_bucket_read(currentBucket, &data, &len, APR_NONBLOCK_READ);
+ if( s != APR_SUCCESS ) {
+ ap_log_rerror( APLOG_MARK, APLOG_ERR, 0, f->r,
+ "IDLCHUNK error reading data from filter with status %d", s);
+ if (params) osrfStringArrayFree(params);
+ if (mparams) osrfStringArrayFree(mparams);
+ return s;
+ }
+
+ if (len > 0) {
+
+ ap_log_rerror( APLOG_MARK, APLOG_DEBUG,
+ 0, f->r, "IDLCHUNK read %d bytes", (int)len);
+
+ /* push data into the XML push parser */
+ if ( XML_Parse(ctx->parser, data, len, 0) == XML_STATUS_ERROR ) {
+
+ char tmp[len+1];
+ memcpy(tmp, data, len);
+ tmp[len] = '\0';
+
+ /* log and die on XML errors */
+ ap_log_rerror( APLOG_MARK, APLOG_ERR, 0, f->r,
+ "IDLCHUNK XML Parse Error: %s at line %d: parsing %s: data %s",
+ XML_ErrorString(XML_GetErrorCode(ctx->parser)),
+ (int) XML_GetCurrentLineNumber(ctx->parser), f->r->filename, tmp);
+
+ XML_ParserFree(parser);
+ if (params) osrfStringArrayFree(params);
+ if (mparams) osrfStringArrayFree(mparams);
+ parser = NULL;
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ }
+
+ /* so a subrequest doesn't re-read this bucket */
+ apr_bucket_delete(currentBucket);
+ }
+
+ apr_brigade_destroy(brigade);
+ if (params) osrfStringArrayFree(params);
+ if (mparams) osrfStringArrayFree(mparams);
+ return APR_SUCCESS;
+}
+
+
+/* Register the filter function as a filter for modifying the HTTP body (content) */
+static void idlChunkRegisterHook(apr_pool_t *pool) {
+ ap_register_output_filter("IDLCHUNK", idlChunkHandler, NULL, AP_FTYPE_CONTENT_SET);
+}
+
+/* Define the module data */
+module AP_MODULE_DECLARE_DATA idlchunk_module = {
+ STANDARD20_MODULE_STUFF,
+ idlChunkCreateDirConfig, /* dir config creater */
+ NULL, /* dir merger --- default is to override */
+ NULL, /* server config */
+ NULL, /* merge server config */
+ idlChunkCommands, /* command apr_table_t */
+ idlChunkRegisterHook /* register hook */
+};
+
+
+
+
More information about the open-ils-commits
mailing list