LP#1796945 Reporter cloning and creation fixes
[working/Evergreen.git] / Open-ILS / src / apachemods / mod_idlchunk.c
1 #include "httpd.h"
2 /* vim:noet:ts=4
3  */
4 #include "http_config.h"
5 #include "http_core.h"
6 #include "http_protocol.h"
7 #include "http_request.h"
8 //#include "apr_compat.h"
9 #include "apr_strings.h"
10 #include "apr_reslist.h"
11 #include "http_log.h"
12 #include "util_filter.h"
13 #include "opensrf/string_array.h"
14 #include "opensrf/utils.h"
15 #include "opensrf/log.h"
16
17 #include <sys/types.h>
18 #include <unistd.h>
19 #include <expat.h>
20
21 #define APACHE_TOOLS_MAX_POST_SIZE 10485760 /* 10 MB */
22 #define MODULE_NAME     "idlchunk_module"
23
24 /* Define the config defaults here */
25 #define MODIDLCHUNK_CONFIG_STRIP_COMMENTS "IDLChunkStripComments" 
26 #define MODIDLCHUNK_CONFIG_CONTENT_TYPE "IDLChunkContentType"
27 #define MODIDLCHUNK_CONFIG_CONTENT_TYPE_DEFAULT "text/html"
28 #define MODIDLCHUNK_CONFIG_STRIP_PI "IDLChunkStripPI"  
29 #define MODIDLCHUNK_CONFIG_DOCTYPE "IDLChunkDoctype"
30 #define MODIDLCHUNK_CONFIG_STRIP_DOCTYPE "IDLChunkStripDoctype"
31 #define MODIDLCHUNK_CONFIG_ESCAPE_SCRIPT "IDLChunkEscapeScript"
32
33 module AP_MODULE_DECLARE_DATA idlchunk_module;
34
35 int idlChunkInScript = 0; /* are we in the middle of a <script> tag */
36 osrfStringArray* mparams = NULL;
37
38 int inChunk = 0;
39 int all = 0;
40
41 /* our context */
42 typedef struct {
43         apr_bucket_brigade* brigade; /* the bucket brigade we buffer our data into */
44         XML_Parser parser; /* our XML parser */
45 } idlChunkContext;
46
47 /* our config data */
48 typedef struct {
49         int stripComments;      /* should we strip comments on the way out? */
50         int stripPI;                    /* should we strip processing instructions on the way out? */
51         int stripDoctype;
52         int escapeScript;               /* if true, we html-escape anything text inside a <script> tag */
53         char* contentType;      /* the content type used to server pages */
54         char* doctype;                  /* the doctype header to send before any other data */
55 } idlChunkConfig;
56
57
58 static osrfStringArray* apacheParseParms(request_rec* r) {
59
60         if( r == NULL ) return NULL;
61         //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "got a valid request_rec");
62
63         char* arg = NULL;
64         apr_pool_t *p = r->pool;        /* memory pool */
65         growing_buffer* buffer = buffer_init(1025);
66
67         /* gather the post args and append them to the url query string */
68         if( !strcmp(r->method,"POST") ) {
69
70                 ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK);
71                 
72                 //osrfLogDebug(OSRF_LOG_MARK, "gateway reading post data..");
73             //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "idlchunk reading post data..");
74
75                 if(ap_should_client_block(r)) {
76
77
78                         /* Start with url query string, if any */
79                         
80                         if(r->args && r->args[0])
81                                 buffer_add(buffer, r->args);
82
83                         char body[1025];
84
85                         //osrfLogDebug(OSRF_LOG_MARK, "gateway client has post data, reading...");
86
87                         /* Append POST data */
88                         
89                         long bread;
90                         while( (bread = ap_get_client_block(r, body, sizeof(body) - 1)) ) {
91
92                                 if(bread < 0) {
93                                         //osrfLogInfo(OSRF_LOG_MARK, 
94                                         //      "ap_get_client_block(): returned error, exiting POST reader");
95                                         break;
96                                 }
97
98                                 body[bread] = '\0';
99                                 buffer_add( buffer, body );
100
101                                 //osrfLogDebug(OSRF_LOG_MARK, 
102                                 //      "gateway read %ld bytes: %d bytes of data so far", bread, buffer->n_used);
103
104                                 if(buffer->n_used > APACHE_TOOLS_MAX_POST_SIZE) {
105                                         //osrfLogError(OSRF_LOG_MARK, "gateway received POST larger "
106                                         //      "than %d bytes. dropping request", APACHE_TOOLS_MAX_POST_SIZE);
107                                         buffer_free(buffer);
108                                         return NULL;
109                                 }
110                         }
111
112                         //osrfLogDebug(OSRF_LOG_MARK, "gateway done reading post data");
113                 }
114
115         } else { /* GET */
116
117         if(r->args && r->args[0])
118             buffer_add(buffer, r->args);
119             //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "idlchunk read GET data..");
120     }
121
122
123     if(buffer->n_used > 0)
124         arg = apr_pstrdup(p, buffer->buf);
125     else
126         arg = NULL; 
127     buffer_free(buffer);
128
129         if( !arg || !arg[0] ) { /* we received no request */
130                 return NULL;
131         }
132
133         //osrfLogDebug(OSRF_LOG_MARK, "parsing URL params from post/get request data: %s", arg);
134         //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "parsing URL params from post/get request data: %s", arg);
135         
136         osrfStringArray* sarray         = osrfNewStringArray(12); /* method parameters */
137         int sanity = 0;
138         char* key                                       = NULL; /* query item name */
139         char* val                                       = NULL; /* query item value */
140
141         /* Parse the post/get request data into a series of name/value pairs.   */
142         /* Load each name into an even-numbered slot of an osrfStringArray, and */
143         /* the corresponding value into the following odd-numbered slot.        */
144
145         while( arg && (val = ap_getword(p, (const char**) &arg, '&'))) {
146
147                 key = ap_getword(r->pool, (const char**) &val, '=');
148                 if(!key || !key[0])
149                         break;
150
151                 ap_unescape_url(key);
152                 ap_unescape_url(val);
153
154                 //osrfLogDebug(OSRF_LOG_MARK, "parsed URL params %s=%s", key, val);
155
156                 osrfStringArrayAdd(sarray, key);
157                 osrfStringArrayAdd(sarray, val);
158
159                 if( sanity++ > 1000 ) {
160                         //osrfLogError(OSRF_LOG_MARK, 
161                         //      "Parsing URL params failed sanity check: 1000 iterations");
162                         osrfStringArrayFree(sarray);
163                         return NULL;
164                 }
165
166         }
167
168         //osrfLogDebug(OSRF_LOG_MARK,
169         //      "Apache tools parsed %d params key/values", sarray->size / 2 );
170
171         return sarray;
172 }
173
174
175
176 static osrfStringArray* apacheGetParamKeys(osrfStringArray* params) {
177         if(params == NULL) return NULL; 
178         osrfStringArray* sarray = osrfNewStringArray(12);
179         int i;
180         //osrfLogDebug(OSRF_LOG_MARK, "Fetching URL param keys");
181         for( i = 0; i < params->size; i++ ) 
182                 osrfStringArrayAdd(sarray, osrfStringArrayGetString(params, i++));
183         return sarray;
184 }
185
186 static osrfStringArray* apacheGetParamValues(osrfStringArray* params, char* key) {
187
188         if(params == NULL || key == NULL) return NULL;  
189         osrfStringArray* sarray = osrfNewStringArray(12);
190
191         //osrfLogDebug(OSRF_LOG_MARK, "Fetching URL values for key %s", key);
192         int i;
193         for( i = 0; i < params->size; i++ ) {
194                 const char* nkey = osrfStringArrayGetString(params, i++);
195                 if(nkey && !strcmp(nkey, key)) 
196                         osrfStringArrayAdd(sarray, osrfStringArrayGetString(params, i));
197         }
198         return sarray;
199 }
200
201
202 static char* apacheGetFirstParamValue(osrfStringArray* params, char* key) {
203         if(params == NULL || key == NULL) return NULL;  
204
205         int i;
206         //osrfLogDebug(OSRF_LOG_MARK, "Fetching first URL value for key %s", key);
207         for( i = 0; i < params->size; i++ ) {
208                 const char* nkey = osrfStringArrayGetString(params, i++);
209                 if(nkey && !strcmp(nkey, key)) 
210                         return strdup(osrfStringArrayGetString(params, i));
211         }
212
213         return NULL;
214 }
215
216
217 static int apacheDebug( char* msg, ... ) {
218         VA_LIST_TO_STRING(msg);
219         fprintf(stderr, "%s\n", VA_BUF);
220         fflush(stderr);
221         return 0;
222 }
223
224
225 static int apacheError( char* msg, ... ) {
226         VA_LIST_TO_STRING(msg);
227         fprintf(stderr, "%s\n", VA_BUF);
228         fflush(stderr);
229         return HTTP_INTERNAL_SERVER_ERROR; 
230 }
231
232
233
234
235 /* get the content type from the config */
236 static const char* idlChunkSetContentType(cmd_parms *params, void *cfg, const char *arg) {
237         idlChunkConfig* config = (idlChunkConfig*) cfg;
238         config->contentType = (char*) arg;
239         return NULL;
240 }
241
242
243 /* get the strip PI flag from the config */
244 static const char* idlChunkSetStripPI(cmd_parms *params, void *cfg, const char *arg) {
245         idlChunkConfig* config = (idlChunkConfig*) cfg;
246         char* a = (char*) arg;
247         config->stripPI = (a && !strcasecmp(a, "yes")) ? 1 : 0;
248         return NULL;
249 }
250
251 /* Get the strip comments flag from the config */
252 static const char* idlChunkSetStripComments(cmd_parms *params, void *cfg, const char *arg) {
253         idlChunkConfig* config = (idlChunkConfig*) cfg;
254         char* a = (char*) arg;
255         config->stripComments = (a && !strcasecmp(a, "yes")) ? 1 : 0;
256         return NULL;
257 }
258
259 static const char* idlChunkSetEscapeScript(cmd_parms *params, void *cfg, const char *arg) {
260         idlChunkConfig* config = (idlChunkConfig*) cfg;
261         char* a = (char*) arg;
262         config->escapeScript = (a && !strcasecmp(a, "yes")) ? 1 : 0;
263         return NULL;
264 }
265
266 static const char* idlChunkSetStripDoctype(cmd_parms *params, void *cfg, const char *arg) {
267         idlChunkConfig* config = (idlChunkConfig*) cfg;
268         char* a = (char*) arg;
269         config->stripDoctype = (a && !strcasecmp(a, "yes")) ? 1 : 0;
270         return NULL;
271 }
272
273
274 /* Get the user defined doctype from the config */
275 static const char* idlChunkSetDoctype(cmd_parms *params, void *cfg, const char *arg) {
276         idlChunkConfig* config = (idlChunkConfig*) cfg;
277         config->doctype = (char*) arg;
278         return NULL;
279 }
280
281 /* Tell apache how to set our config variables */
282 static const command_rec idlChunkCommands[] = {
283         AP_INIT_TAKE1( MODIDLCHUNK_CONFIG_STRIP_COMMENTS, 
284                         idlChunkSetStripComments, NULL, ACCESS_CONF, "IDLCHUNK Strip Comments"),
285         AP_INIT_TAKE1( MODIDLCHUNK_CONFIG_CONTENT_TYPE, 
286                         idlChunkSetContentType, NULL, ACCESS_CONF, "IDLCHUNK Content Type"),
287         AP_INIT_TAKE1( MODIDLCHUNK_CONFIG_STRIP_PI,
288                         idlChunkSetStripPI, NULL, ACCESS_CONF, "IDLCHUNK Strip XML Processing Instructions"),
289         AP_INIT_TAKE1( MODIDLCHUNK_CONFIG_DOCTYPE,
290                         idlChunkSetDoctype, NULL, ACCESS_CONF, "IDLCHUNK Doctype Declaration"),
291         AP_INIT_TAKE1( MODIDLCHUNK_CONFIG_STRIP_DOCTYPE,
292                         idlChunkSetStripDoctype, NULL, ACCESS_CONF, "IDLCHUNK Strip Doctype Declaration"),
293         AP_INIT_TAKE1( MODIDLCHUNK_CONFIG_ESCAPE_SCRIPT,
294                         idlChunkSetEscapeScript, NULL, ACCESS_CONF, "IDLCHUNK Escape data in script tags"),
295         {NULL}
296 };
297
298 /* Creates a new config object */
299 static void* idlChunkCreateDirConfig( apr_pool_t* p, char* dir ) {
300         idlChunkConfig* config = 
301                 (idlChunkConfig*) apr_palloc( p, sizeof(idlChunkConfig) );
302
303         config->stripComments = 0;
304         config->stripPI       = 0;
305         config->stripDoctype  = 1;
306         config->escapeScript     = 1;
307         config->contentType      = MODIDLCHUNK_CONFIG_CONTENT_TYPE_DEFAULT;
308         config->doctype       = NULL;
309
310         return (void*) config;
311 }
312
313 /* keep for a while in case we ever need it */
314 /*
315 #define IDLCHUNK_INHERIT(p, c, f) ((c->f) ? c->f : p->f);
316 static void* idlChunkMergeDirConfig(apr_pool_t *p, void *base, void *overrides) {
317         idlChunkConfig* parent          = base;
318         idlChunkConfig* child           = overrides;
319         idlChunkConfig* newConf = (idlChunkConfig*) apr_pcalloc(p, sizeof(idlChunkConfig));
320         newConf->contentType = IDLCHUNK_INHERIT(parent, child, contentType);
321         newConf->stripComments = IDLCHUNK_INHERIT(parent, child, stripComments);
322         return newConf;
323 }
324 */
325
326
327 /* We need a global parser object because sub-requests, with different
328  * filter contexts, are parsing part of the same document.
329  * This means that this filter will only work in forked (non-threaded) environments.
330  * XXX Figure out how to share pointers/data accross filters */
331 XML_Parser parser = NULL;
332
333 /* utility function which passes data to the next filter */
334 static void _fwrite( ap_filter_t* filter, char* data, ... ) {
335         if(!(filter && data)) return;
336         idlChunkContext* ctx = (idlChunkContext*) filter->ctx;
337         VA_LIST_TO_STRING(data);
338         ap_fwrite( filter->next, ctx->brigade, VA_BUF, strlen(VA_BUF));
339 }
340
341
342 /** XXX move me to  opensrf/utils.h */
343 #define OSRF_UTILS_REPLACE_CHAR(str, o, n)\
344         do {\
345                 int i = 0;\
346                 while(str[i] != '\0') {\
347                         if(str[i] == o)\
348                                 str[i] = n;\
349                         i++;\
350                 }\
351         } while(0)
352
353 /* cycles through the attributes attached to an element */
354 static char* find_id_attr( const char** atts ) {
355         if(!atts) return NULL;
356         int i;
357         for( i = 0; atts[i] && atts[i+1]; i++ ) {
358                 const char* name = atts[i];
359                 char* value = (char*)atts[i+1];
360         if (!strcmp(name,"id")) return value;
361                 i++;
362         }
363
364         /* In case we don't find anything to return */
365         return NULL;
366 }
367
368 /* cycles through the attributes attached to an element */
369 static void printAttr( ap_filter_t* filter, const char** atts ) {
370         if(!atts) return;
371         int i;
372         for( i = 0; atts[i] && atts[i+1]; i++ ) {
373                 const char* name = atts[i];
374                 const char* value = atts[i+1];
375                 char* escaped = ap_escape_html(filter->r->pool, value); 
376
377                 /* we make a big assumption here that if the string contains a ', 
378                  * then the original attribute was wrapped in "s - so recreate that */
379                 if( strchr( escaped, '\'' ) ) {
380                         OSRF_UTILS_REPLACE_CHAR(escaped,'"','\'');
381                         _fwrite( filter, " %s=\"%s\"", name, escaped );
382
383                 } else {
384                         OSRF_UTILS_REPLACE_CHAR(escaped,'\'','"');
385                         _fwrite( filter, " %s='%s'", name, escaped );
386                 }
387
388                 i++;
389         }
390 }
391
392 /* Starts an XML element */
393 static void XMLCALL startElement(void *userData, const char *name, const char **atts) {
394
395     ap_filter_t* filter = (ap_filter_t*) userData;
396
397
398     if (!strcmp(name,"class")) {
399         //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, filter->r,"Looking at %s with id of %s",name, find_id_attr(atts));
400
401         if (osrfStringArrayContains(mparams, find_id_attr(atts))) {
402             inChunk = 1;
403                 //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, filter->r,"Found desired class %s", find_id_attr(atts));
404         }
405     }
406
407     if (all || inChunk || (name && (!strcmp(name,"IDL")))) {
408
409             idlChunkConfig* config = ap_get_module_config( 
410                         filter->r->per_dir_config, &idlchunk_module );
411         _fwrite(filter, "<%s", name );
412             printAttr( filter, atts );
413         if (!strncmp(config->contentType, MODIDLCHUNK_CONFIG_CONTENT_TYPE_DEFAULT, 9)) {
414                 _fwrite(filter, " />", name );
415         } else {
416                 _fwrite(filter, ">", name );
417         }
418             if(!strcmp(name, "script")) 
419                 idlChunkInScript = 1;
420     }
421 }
422
423 /* Handles the character data */
424 static void XMLCALL charHandler( void* userData, const XML_Char* s, int len ) {
425         ap_filter_t* filter = (ap_filter_t*) userData;
426         char data[len+1];
427         memset( data, '\0', sizeof(data) );
428         memcpy( data, s, len );
429
430         idlChunkConfig* config = ap_get_module_config( 
431                         filter->r->per_dir_config, &idlchunk_module );
432
433     if (all || inChunk) {
434         if( idlChunkInScript && ! config->escapeScript ) {
435                 _fwrite( filter, "%s", data );
436
437         } else {
438                 char* escaped = ap_escape_html(filter->r->pool, data);
439                 _fwrite( filter, "%s", escaped );
440             } 
441     }
442 }
443
444 static void XMLCALL handlePI( void* userData, const XML_Char* target, const XML_Char* data) {
445         ap_filter_t* filter = (ap_filter_t*) userData;
446         _fwrite(filter, "<?%s %s?>", target, data);
447 }
448
449 static void XMLCALL handleComment( void* userData, const XML_Char* comment ) {
450         ap_filter_t* filter = (ap_filter_t*) userData;
451         _fwrite(filter, "<!-- %s -->", comment);
452 }
453
454 /* Ends an XML element */
455 static void XMLCALL endElement(void *userData, const char *name) {
456
457     if (all || inChunk || (name && (!strcmp(name,"IDL")))) {
458
459         ap_filter_t* filter = (ap_filter_t*) userData;
460         idlChunkConfig* config = ap_get_module_config( 
461                         filter->r->per_dir_config, &idlchunk_module );
462         if (!strncmp(config->contentType, MODIDLCHUNK_CONFIG_CONTENT_TYPE_DEFAULT, 9)) { 
463                 return;
464         }
465         _fwrite( filter, "</%s>", name );
466         if(!strcmp(name, "script")) 
467                 idlChunkInScript = 1;
468     
469     }
470     if (!strcmp(name,"class")) inChunk = 0;
471 }
472
473 static void XMLCALL doctypeHandler( void* userData, 
474         const char* name, const char* sysid, const char* pubid, int hasinternal ) {
475
476         ap_filter_t* filter = (ap_filter_t*) userData;
477         char* s = (sysid) ? (char*) sysid : "";
478         char* p = (pubid) ? (char*) pubid : "";
479         _fwrite( filter, "<!DOCTYPE %s PUBLIC \"%s\" \"%s\">\n", name, p, s );
480 }
481
482
483 /* The handler.  Create a new parser and/or filter context where appropriate
484  * and parse the chunks of data received from the brigade
485  */
486 static int idlChunkHandler( ap_filter_t *f, apr_bucket_brigade *brigade ) {
487
488         idlChunkContext* ctx = f->ctx;
489         apr_bucket* currentBucket = NULL;
490         apr_pool_t* pool = f->r->pool;
491         const char* data;
492         apr_size_t len;
493     osrfStringArray* params = NULL;
494     mparams = NULL;
495
496         /* load the per-dir/location config */
497         idlChunkConfig* config = ap_get_module_config( 
498                         f->r->per_dir_config, &idlchunk_module );
499
500         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 
501                         0, f->r, "IDLCHUNK Config:\nContent Type = %s, "
502                         "Strip PI = %s, Strip Comments = %s, Doctype = %s", 
503                         config->contentType, 
504                         (config->stripPI) ? "yes" : "no", 
505                         (config->stripComments) ? "yes" : "no",
506                         config->doctype);
507
508         /* set the content type based on the config */
509         ap_set_content_type(f->r, config->contentType);
510
511         //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, "Set content type");
512
513     params = apacheParseParms(f->r); /* free me */
514     mparams = apacheGetParamValues( params, "class" ); /* free me */
515
516     all = 1;
517
518     if (mparams && mparams->size > 0) all = 0;
519
520         //ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, "Parsed the params, if any");
521
522         /* create the XML parser */
523         int firstrun = 0;
524         if( parser == NULL ) {
525                 firstrun = 1;
526                 parser = XML_ParserCreate("UTF-8");
527                 XML_SetUserData(parser, f);
528                 XML_SetElementHandler(parser, startElement, endElement);
529                 XML_SetCharacterDataHandler(parser, charHandler);
530                 if(!config->stripDoctype)
531                         XML_SetStartDoctypeDeclHandler( parser, doctypeHandler );
532                 if(!config->stripPI)
533                         XML_SetProcessingInstructionHandler(parser, handlePI);
534                 if(!config->stripComments)
535                         XML_SetCommentHandler(parser, handleComment);
536         }
537
538         /* create the filter context */
539         if( ctx == NULL ) {
540                 f->ctx = ctx = apr_pcalloc( pool, sizeof(*ctx));
541                 ctx->brigade = apr_brigade_create( pool, f->c->bucket_alloc );
542                 ctx->parser = parser;
543         }
544
545
546         if(firstrun) { /* we haven't started writing the data to the stream yet */
547
548                 /* go ahead and write the doctype out if we have one defined */
549                 if(config->doctype) {
550                         ap_log_rerror( APLOG_MARK, APLOG_DEBUG, 
551                                         0, f->r, "IDLCHUNK DOCTYPE => %s", config->doctype);
552                         _fwrite(f, "%s\n", config->doctype);
553                 }
554         }
555
556
557         /* cycle through the buckets in the brigade */
558         while (!APR_BRIGADE_EMPTY(brigade)) {
559
560                 /* grab the next bucket */
561                 currentBucket = APR_BRIGADE_FIRST(brigade);
562
563                 /* clean up when we're done */
564                 if (APR_BUCKET_IS_EOS(currentBucket) || APR_BUCKET_IS_FLUSH(currentBucket)) {
565                 APR_BUCKET_REMOVE(currentBucket);
566                         APR_BRIGADE_INSERT_TAIL(ctx->brigade, currentBucket);
567                         ap_pass_brigade(f->next, ctx->brigade);
568                         XML_ParserFree(parser);
569             if (params) osrfStringArrayFree(params);
570             if (mparams) osrfStringArrayFree(mparams);
571                         parser = NULL;
572                         return APR_SUCCESS;
573         }
574
575                 /* read the incoming data */
576                 int s = apr_bucket_read(currentBucket, &data, &len, APR_NONBLOCK_READ);
577                 if( s != APR_SUCCESS ) {
578                         ap_log_rerror( APLOG_MARK, APLOG_ERR, 0, f->r, 
579                                         "IDLCHUNK error reading data from filter with status %d", s);
580             if (params) osrfStringArrayFree(params);
581             if (mparams) osrfStringArrayFree(mparams);
582                         return s;
583                 }
584
585                 if (len > 0) {
586
587                         ap_log_rerror( APLOG_MARK, APLOG_DEBUG, 
588                                         0, f->r, "IDLCHUNK read %d bytes", (int)len);
589
590                         /* push data into the XML push parser */
591                         if ( XML_Parse(ctx->parser, data, len, 0) == XML_STATUS_ERROR ) {
592
593                 char tmp[len+1];
594                 memcpy(tmp, data, len);
595                 tmp[len] = '\0';
596
597                                 /* log and die on XML errors */
598                                 ap_log_rerror( APLOG_MARK, APLOG_ERR, 0, f->r, 
599                     "IDLCHUNK XML Parse Error: %s at line %d: parsing %s: data %s",
600                                         XML_ErrorString(XML_GetErrorCode(ctx->parser)), 
601                                         (int) XML_GetCurrentLineNumber(ctx->parser), f->r->filename, tmp);
602
603                                 XML_ParserFree(parser);
604                 if (params) osrfStringArrayFree(params);
605                 if (mparams) osrfStringArrayFree(mparams);
606                                 parser = NULL;
607                                 return HTTP_INTERNAL_SERVER_ERROR; 
608                         }
609         }
610
611                 /* so a subrequest doesn't re-read this bucket */
612                 apr_bucket_delete(currentBucket); 
613         }
614
615         apr_brigade_destroy(brigade);
616     if (params) osrfStringArrayFree(params);
617     if (mparams) osrfStringArrayFree(mparams);
618         return APR_SUCCESS;     
619 }
620
621
622 /* Register the filter function as a filter for modifying the HTTP body (content) */
623 static void idlChunkRegisterHook(apr_pool_t *pool) {
624   ap_register_output_filter("IDLCHUNK", idlChunkHandler, NULL, AP_FTYPE_CONTENT_SET);
625 }
626
627 /* Define the module data */
628 module AP_MODULE_DECLARE_DATA idlchunk_module = {
629   STANDARD20_MODULE_STUFF,
630   idlChunkCreateDirConfig,      /* dir config creater */
631   NULL,                                                 /* dir merger --- default is to override */
632   NULL,                                       /* server config */
633   NULL,                    /* merge server config */
634   idlChunkCommands,          /* command apr_table_t */
635   idlChunkRegisterHook                  /* register hook */
636 };
637
638
639
640