From: erickson Date: Thu, 4 Aug 2005 22:13:11 +0000 (+0000) Subject: apachetools is some generic apache module helper functions X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=a92e51b40a7ea43e0df2c058bc2492bb50d7d1b0;p=working%2FOpenSRF.git apachetools is some generic apache module helper functions xmltools are some generic xml helper functions mod_xmltools is the beginning of our XML monster for processing DTDs, xincludes, and potentially xslt's git-svn-id: svn://svn.open-ils.org/OpenSRF/trunk@464 9efc2488-bf62-4759-914b-345cdb29e865 --- diff --git a/src/apachemods/Makefile b/src/apachemods/Makefile new file mode 100644 index 0000000..1932c7e --- /dev/null +++ b/src/apachemods/Makefile @@ -0,0 +1,27 @@ +LD_OPTS += -lxml2 -lc_utils + +all: mod_xmltools.so + +mod_xmltools.so: apachetools.o xmltools.o + $(CC) -c $(CC_OPTS) mod_xmltools.c + $(CC) $(LD_OPTS) -shared -W1 apachetools.o xmltools.o mod_xmltools.o -o $@ + +apachetools.o: apachetools.c apachetools.h + $(CC) -c $(CC_OPTS) apachetools.c -o $@ + +xmltools.o: xmltools.c xmltools.h + $(CC) -c $(CC_OPTS) xmltools.c -o $@ + + +install: + $(APXS2) -i -a -n mod_xmltools mod_xmltools.so + @echo "-----------------------------------------------"; + @echo -e "* Important * : Change httpd.conf from this: \n \ + LoadModule mod_xmltools_module modules/mod_xmltools.so \n \ + to this: \n \ + LoadModule mod_xmltools modules/mod_xmltools.so" + @echo "-----------------------------------------------"; + @sleep 3; + +clean: + /bin/rm -f *.o xmltools diff --git a/src/apachemods/apachetools.c b/src/apachemods/apachetools.c new file mode 100644 index 0000000..2891d15 --- /dev/null +++ b/src/apachemods/apachetools.c @@ -0,0 +1,113 @@ +#include "apachetools.h" + +string_array* apacheParseParms(request_rec* r) { + + if( r == NULL ) return NULL; + + char* arg = r->args; /* url query string */ + apr_pool_t *p = r->pool; /* memory pool */ + string_array* sarray = init_string_array(12); /* method parameters */ + + growing_buffer* buffer = NULL; /* POST data */ + growing_buffer* tmp_buf = NULL; /* temp buffer */ + + char* key = NULL; /* query item name */ + char* val = NULL; /* query item value */ + + + /* 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); + + if(ap_should_client_block(r)) { + + char body[1025]; + memset(body,0,1025); + buffer = buffer_init(1025); + + while(ap_get_client_block(r, body, 1024)) { + buffer_add( buffer, body ); + memset(body,0,1025); + } + + if(arg && arg[0]) { + + tmp_buf = buffer_init(1024); + buffer_add(tmp_buf,arg); + buffer_add(tmp_buf,buffer->buf); + arg = (char*) apr_pstrdup(p, tmp_buf->buf); + buffer_free(tmp_buf); + + } else { + arg = (char*) apr_pstrdup(p, buffer->buf); + } + + buffer_free(buffer); + } + } + + + if( ! arg || !arg[0] ) { /* we received no request */ + return NULL; + } + + + 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((char*)key); + ap_unescape_url((char*)val); + + string_array_add(sarray, key); + string_array_add(sarray, val); + + } + + return sarray; + +} + + + +string_array* apacheGetParamKeys(string_array* params) { + if(params == NULL) return NULL; + string_array* sarray = init_string_array(12); + int i; + for( i = 0; i < params->size; i++ ) + string_array_add(sarray, string_array_get_string(params, i++)); + return sarray; +} + +string_array* apacheGetParamValues(string_array* params, char* key) { + + if(params == NULL || key == NULL) return NULL; + string_array* sarray = init_string_array(12); + + int i; + for( i = 0; i < params->size; i++ ) { + char* nkey = string_array_get_string(params, i++); + if(key && !strcmp(nkey, key)) + string_array_add(sarray, string_array_get_string(params, i)); + } + return sarray; +} + + +char* apacheGetFirstParamValue(string_array* params, char* key) { + if(params == NULL || key == NULL) return NULL; + + int i; + for( i = 0; i < params->size; i++ ) { + char* nkey = string_array_get_string(params, i++); + if(key && !strcmp(nkey, key)) + return strdup(string_array_get_string(params, i)); + } + + return NULL; +} + + diff --git a/src/apachemods/apachetools.h b/src/apachemods/apachetools.h new file mode 100644 index 0000000..d082c57 --- /dev/null +++ b/src/apachemods/apachetools.h @@ -0,0 +1,37 @@ +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_protocol.h" +#include "apr_compat.h" +#include "apr_strings.h" + +#include "string_array.h" +#include "utils.h" + +#ifndef APACHE_TOOLS_H +#define APACHE_TOOLS_H + + +/* parses apache URL params (GET and POST). + Returns a string_array of the form [ key, val, key, val, ...] + Returns NULL if there are no params */ +string_array* apacheParseParms(request_rec* r); + +/* provide the params string array, and this will generate a + string of array of param keys + the returned string_array most be freed by the caller + */ +string_array* apacheGetParamKeys(string_array* params); + +/* provide the params string array and a key name, and + this will provide the value found for that key + the returned string_array most be freed by the caller + */ +string_array* apacheGetParamValues(string_array* params, char* key); + +/* returns the first value found for the given param. + char* must be freed by the caller */ +char* apacheGetFirstParamValue(string_array* params, char* key); + + +#endif diff --git a/src/apachemods/mod_xmltools.c b/src/apachemods/mod_xmltools.c new file mode 100644 index 0000000..41caeb6 --- /dev/null +++ b/src/apachemods/mod_xmltools.c @@ -0,0 +1,116 @@ +#include "apachetools.h" +#include "xmltools.h" + +#define MODULE_NAME "mod_xmltools" /* our module name */ +#define PARAM_LOCALE "locale" /* the URL param for the local directory */ +#define LANG_DTD "lang.dtd" /* the DTD for the test entities */ + +/* these should be config directives */ +#define LOCALE_DIR "/home/erickson/sandbox/apachemods/locale" /* The root directory where the local files are stored */ +#define DEFAULT_LOCALE "en-US" /* If no locale data is provided */ + + +/* Child Init */ +static void mod_xmltools_child_init(apr_pool_t *p, server_rec *s) { +} + +/* allocates a char* to hold the name of the DTD language file + Prints to stderr and returns NULL if there was an error loading the file + */ + +static char* get_dtd_lang_file(string_array* params) { + + char* localedir = apacheGetFirstParamValue(params, PARAM_LOCALE); + if(!localedir) localedir = strdup(DEFAULT_LOCALE); + + int len = strlen(LANG_DTD) + strlen(localedir) + strlen(LOCALE_DIR) + 1; + char dtdfile[len]; + bzero(dtdfile, len); + + if(localedir) + sprintf(dtdfile, "%s/%s/%s", LOCALE_DIR, localedir, LANG_DTD ); + + return strdup(dtdfile); +} + +static int mod_xmltools_handler (request_rec* r) { + + /* make sure we're needed first thing*/ + if (strcmp(r->handler, MODULE_NAME )) + return DECLINED; + + /* we accept get/post requests */ + r->allowed |= (AP_METHOD_BIT << M_GET); + r->allowed |= (AP_METHOD_BIT << M_POST); + + ap_set_content_type(r, "text/html"); + + string_array* params = apacheParseParms(r); + + char* file = r->filename; + char* dtdfile = get_dtd_lang_file(params); + + xmlDocPtr doc; + + /* be explicit */ + xmlSubstituteEntitiesDefault(0); + + /* parse the doc */ + if( (doc = xmlParseFile(file)) == NULL) { + fprintf(stderr, "\n ^-- Error parsing XML file %s\n", file); + fflush(stderr); + return HTTP_INTERNAL_SERVER_ERROR; + } + + /* process xincludes */ + if( xmlXIncludeProcess(doc) < 0 ) { + fprintf(stderr, "\n ^-- Error processing XIncludes for file %s\n", file); + fflush(stderr); + return HTTP_INTERNAL_SERVER_ERROR; + } + + + /* replace the DTD */ + if(xmlReplaceDtd(doc, dtdfile) < 0) { + fprintf(stderr, "Error replacing DTD file with file %s\n", dtdfile); + fflush(stderr); + return HTTP_INTERNAL_SERVER_ERROR; + } + + + /* force DTD entity replacement */ + doc = xmlProcessDtdEntities(doc); + + /* stringify */ + char* xml = xmlDocToString(doc, 0); + + /* print the doc */ + ap_rputs(xml, r); + + /* deallocate */ + free(dtdfile); + free(xml); + xmlFreeDoc(doc); + xmlCleanupCharEncodingHandlers(); + xmlCleanupParser(); + + return OK; + +} + + +static void mod_xmltools_register_hooks (apr_pool_t *p) { + ap_hook_handler(mod_xmltools_handler, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_child_init(mod_xmltools_child_init,NULL,NULL,APR_HOOK_MIDDLE); +} + +module AP_MODULE_DECLARE_DATA mod_xmltools = { + STANDARD20_MODULE_STUFF, + NULL, + NULL, + NULL, + NULL, + NULL, + mod_xmltools_register_hooks, +}; + diff --git a/src/apachemods/xmltools.c b/src/apachemods/xmltools.c new file mode 100644 index 0000000..fb92b89 --- /dev/null +++ b/src/apachemods/xmltools.c @@ -0,0 +1,130 @@ +#include "xmltools.h" + +#define TEXT_DTD "test2.dtd" + + + +/* +int main( int argc, char* argv[] ) { + + char* file = argv[1]; + char* localedir = argv[2]; + + int len = strlen(TEXT_DTD) + strlen(localedir) + 1; + char dtdfile[len]; + bzero(dtdfile, len); + + if(localedir) + sprintf(dtdfile, "%s/%s", localedir, TEXT_DTD ); + + + if(access(dtdfile, R_OK)) { + fprintf(stderr, "Unable to open DTD file %s\n", dtdfile); + fflush(stderr); + return HTTP_INTERNAL_SERVER_ERROR; + } + + + xmlDocPtr doc; + + xmlSubstituteEntitiesDefault(0); + + + if( (doc = xmlParseFile(file)) == NULL) { + fprintf(stderr, "\n ^-- Error parsing XML file %s\n", file); + fflush(stderr); + return HTTP_INTERNAL_SERVER_ERROR; + } + + if( xmlXIncludeProcess(doc) < 0 ) { + fprintf(stderr, "\n ^-- Error processing XIncludes for file %s\n", file); + fflush(stderr); + return HTTP_INTERNAL_SERVER_ERROR; + } + + xmlReplaceDtd(doc, dtdfile); + + doc = xmlProcessDtdEntities(doc); + + char* xml = xmlDocToString(doc, 0); + + printf("\n%s\n", xml); + + free(xml); + xmlFreeDoc(doc); + xmlCleanupCharEncodingHandlers(); + xmlCleanupParser(); + + return 0; + +} +*/ + +xmlDocPtr xmlProcessDtdEntities(xmlDocPtr doc) { + char* xml = xmlDocToString(doc, 1); + xmlFreeDoc(doc); + xmlSubstituteEntitiesDefault(1); + xmlDocPtr d = xmlParseMemory(xml, strlen(xml)); + free(xml); + return d; +} + + +int xmlReplaceDtd(xmlDocPtr doc, char* dtdfile) { + + if(!doc || !dtdfile) return 0; + + /* remove the original DTD */ + if(doc->children && doc->children->type == XML_DTD_NODE) { + xmlNodePtr p = doc->children; + xmlUnlinkNode(p); + xmlFreeNode(p); + } + + + xmlDtdPtr dtd = xmlParseDTD(NULL, dtdfile); + + if(!dtd) { + fprintf(stderr, "Error parsing DTD file %s\n", dtdfile); + fflush(stderr); + return -1; + } + + fprintf(stderr, "2\n"); + fflush(stderr); + + dtd->name = xmlStrdup((xmlChar*)"x"); + doc->extSubset = dtd; + dtd->doc = doc; + dtd->parent = doc; + xmlNodePtr x = doc->children; + doc->children = (xmlNodePtr)dtd; + dtd->next = x; + + return 1; +} + +char* xmlDocToString(xmlDocPtr doc, int full) { + + char* xml; + + if(full) { + + xmlChar* xmlbuf; + int size; + xmlDocDumpMemory(doc, &xmlbuf, &size); + xml = strdup((char*) (xmlbuf)); + xmlFree(xmlbuf); + return xml; + + } else { + + xmlBufferPtr xmlbuf = xmlBufferCreate(); + xmlNodeDump( xmlbuf, doc, xmlDocGetRootElement(doc), 0, 0); + xml = strdup((char*) (xmlBufferContent(xmlbuf))); + xmlBufferFree(xmlbuf); + return xml; + + } + +} diff --git a/src/apachemods/xmltools.h b/src/apachemods/xmltools.h new file mode 100644 index 0000000..b5baeed --- /dev/null +++ b/src/apachemods/xmltools.h @@ -0,0 +1,39 @@ + +/* general headers */ +#include +#include +#include + +/* libxml2 headers */ +#include +#include +#include +#include +#include + +#include "apachetools.h" + + +#ifndef XMLTOOLS_H +#define XMLTOOLS_H + + +/* turns a doc into a string. string must be deallocated. + if 'full', then the entire doc is stringified, otherwise + the root node (on down) is stringified */ +char* xmlDocToString(xmlDocPtr doc, int full); + +int xmlReplaceDtd(xmlDocPtr doc, char* dtdfile); + +/* Inline DTD Entity replacement. + creates a new doc with the entities replaced, frees the + doc provided and returns a new one. + Do this and you'll be OK: + doc = xmlProcessDtdEntities(doc); + */ +xmlDocPtr xmlProcessDtdEntities(xmlDocPtr doc); + + +#endif + +