/* * DotGNU Execution Environment Apache 2 Module * * Copyright 2001-2003 netFluid Technology Ltd * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * $Revision: 1.1.2.1 $ $Date: 2003/08/31 10:56:36 $ * * -------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../fields/dgfid.h" #include "httpd.h" #include "http_config.h" #include "http_request.h" #include "http_core.h" #include "http_protocol.h" #include "http_main.h" #include "http_log.h" #include "util_script.h" #include "apr_strings.h" #include "apr_pools.h" #define PATHSIZE 127 typedef struct { char *gwconfig; char dgee_resbase[PATHSIZE+1]; } dgee_server_conf; /* ------------------------------------------------------------------------- */ module AP_MODULE_DECLARE_DATA dgee_module; static void dgee_init( server_rec *s, apr_pool_t *p ) { char *sname = s->server_hostname; ap_add_version_component(p,"DotGnu/"DGVERSION ); } /* ------------------------------------------------------------------------- */ static void dgee_cleanup( server_rec *s ) { char *sname = s->server_hostname; gw_release(1); /* Drop connection to Goldwater application (1 = forced) */ } /* ------------------------------------------------------------------------- */ static void * create_dgee_config(apr_pool_t *p, server_rec *s) { dgee_server_conf *c = (dgee_server_conf *) apr_pcalloc(p, sizeof(dgee_server_conf)); c->gwconfig = NULL; return (void *) c; } /* ------------------------------------------------------------------------- */ static void * merge_dgee_config(apr_pool_t *p, void *basev, void *overridesv) { dgee_server_conf *base = (dgee_server_conf *) basev; dgee_server_conf *overrides = (dgee_server_conf *) overridesv; return (void *) (overrides->gwconfig ? overrides : base); } /* ------------------------------------------------------------------------- */ static const char * set_gwconfig(cmd_parms *cmd, void *dummy, const char *arg) { long len = 0; int ix = 0; char path[128] = {0}; char *ep= NULL; server_rec *s = cmd->server; dgee_server_conf *conf = (dgee_server_conf *) ap_get_module_config(s->module_config, &dgee_module); conf->gwconfig = (char *) arg; setenv( "GWCONFIG", conf->gwconfig, 1 ); if( gw_config_init() < 0 ) { ap_log_error(APLOG_MARK,APLOG_ERR, 0, s, "Cannot open DGEE configuration file" ); return NULL; } /* Find env setting DGEE_RESBASE in GWConfig, domain 0 */ if( (ep= (char*)gw_getenv( "DGEE_RESBASE" )) == NULL ) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Initialisation of DGEEGWConfig failed - Missing in '%s' [local domain config]", conf->gwconfig ); ep = ""; } strncpy( conf->dgee_resbase, ep, PATHSIZE ); conf->dgee_resbase[PATHSIZE] = '\0'; gw_config_deinit(); return NULL; } /* ------------------------------------------------------------------------- */ /* Rewrite uri to real location filepaths, or accept 'virtual' uri's */ static int uri2file(request_rec *r) { char buf[256]; int urilen = 0; dgee_server_conf *conf = (dgee_server_conf *)ap_get_module_config(r->server->module_config, &dgee_module); /* If the uri begins with /dgstatic/ then it's a virtual dir - remap to the * real location. */ if( r->uri && strncmp( r->uri, "/dgstatic/", 10 ) == 0 ) { sprintf( buf, "%s/html/%s", conf->dgee_resbase, r->uri + 10); r->filename = apr_pstrdup(r->pool, buf ); return OK; } if( strcmp( r->uri, "/dgee" ) == 0 ) { /* This is a virtual directory */ return OK; } urilen = strlen(r->uri); if( strncmp( r->uri + (urilen - 5), ".dgee", 5 ) == 0 ) { /* A dgee access point, so this is okay too */ return OK; } return DECLINED; } /* ------------------------------------------------------------------------- */ static int dgee_get_doc(request_rec *r) { GWMessage msg = {0}; MsgChain *request = NULL; MsgChain *reply = NULL; char *ctype = NULL; char *html = NULL; char *content = NULL; static char cont_type[64]; char lenstr[20]; void *stream = NULL; char *URI = NULL; char *ARG = NULL; long clen = 0; long len = 0; int ret = 0; /* Doing gw_init() repeatedly is okay as it'll try and keep track of * when it's connected or not */ if( gw_init() < 0 ) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0,r, "Goldwater Initialisation Failed - %s\n", gw_errorstr( gwerror ) ); return HTTP_SERVICE_UNAVAILABLE; } gw_logf( LOG_INTDBG, "Apache mod_dgee client Starting" ); /* Create a request buffer and populate it... */ if( (request = gwmc_create() ) == NULL ) { ap_log_rerror(APLOG_MARK, APLOG_ERR,0, r, "Failed to create request message" ); return HTTP_INTERNAL_SERVER_ERROR; } /* This only works for GET requests */ URI = r->uri; ARG = r->args ? r->args : ""; gwmc_add_data( request, DGF_REQ_URI, MIME_TEXT_PLAIN, URI, strlen(URI) ); gwmc_add_data( request, DGF_REQ_DATA, MIME_TEXT_PLAIN, ARG, strlen(ARG) ); /* Get data stream to send */ if( (stream = gwmc_get_message_ptr( request, &len )) == NULL ) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Failed to get message stream" ); gwmc_destroy( &request ); return HTTP_INTERNAL_SERVER_ERROR; } if( ( ret = gw_svc_call( "/DGEE/SM/GetDoc", stream, len, &msg, 0 )) < 0 ){ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "gw_svc_call failed with code %d [%s]\n", gwerror, gw_errorstr(gwerror) ); gwmc_destroy( &request ); switch( gwerror ) { case GWE_APPERR: /* Act on application errors */ switch( gwusrerr ) { case ERR_NOT_FOUND: return HTTP_NOT_FOUND; default: return HTTP_INTERNAL_SERVER_ERROR; } case GWE_NOSVC: case GWE_SBLOCKD: return HTTP_SERVICE_UNAVAILABLE; default: return HTTP_INTERNAL_SERVER_ERROR; } } /* Instantiate a 'message buffer' from input data */ if( (reply = gwmc_importGWMessage( &msg )) == NULL ) { gw_logf( LOG_ERROR, "Could not instantiate reply message buffer" ); ap_log_rerror(APLOG_MARK, APLOG_ERR,0, r, "DGEE Reply failure" ); } ctype = MIME_TEXT_HTML; html = (char*)gwmc_read_data( reply, DGF_DOC_HTML, &ctype, 1, &len ); content = (char*)gwmc_read_data( reply, DGF_CONTENT_TYPE, &ctype, 1, &clen ); if( !html || len == 0 ) { ap_log_rerror(APLOG_MARK, APLOG_ERR,0, r, "No HTML generated" ); return HTTP_NOT_FOUND; } strncpy( cont_type, content ? content : "text/html", sizeof(cont_type)-1 ); sprintf( lenstr, "%ld", len ); r->content_type = cont_type; apr_table_set(r->headers_out,"Content-Length", lenstr ); apr_table_set(r->headers_out,"X-DGEE-Server", "DotGNU/"DGVERSION";" ); /* ap_send_http_header(r); --> This function is not required any more */ ap_rwrite( html, len, r ); gwmc_destroy( &request ); gwmc_destroy( &reply ); gw_logf( LOG_INTDBG, "Apache mod_dgee client Exiting" ); return OK; /* NOT r->status, even if it has changed. */ } /* ------------------------------------------------------------------------- */ static int dgee_call_service(request_rec *r) { static char buf[HUGE_STRING_LEN] = {0}; GWMessage msg = {0}; MsgChain *request = NULL; MsgChain *reply = NULL; CString bufferCS = CSInit; CString blockCS = CSInit; void *stream = NULL; char *ctype = NULL; char *xml = NULL; char *URI = NULL; char *ARG = NULL; long clen = 0; long len = 0; int ret = 0; char lenstr[20] = {0}; #define CLEANUP_RESOURCES { if( request ) gwmc_destroy( &request ); if( reply ) gwmc_destroy( &reply ); } /* Doing gw_init() repeatedly is okay as it'll try and keep track of * when it's connected or not */ if( gw_init() < 0 ) { ap_log_rerror(APLOG_MARK, APLOG_ERR,0, r, "Goldwater Initialisation Failed - %s\n", gw_errorstr( gwerror ) ); return HTTP_SERVICE_UNAVAILABLE; } gw_logf( LOG_INTDBG, "Apache mod_dgee client Starting" ); if ((ret = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) return ret; /* This only works for POST requests */ URI = r->uri; /* Build up POSTed data buffer */ if( ap_should_client_block(r) ) { int post_len = 0; /* ap_hard_timeout("get script args",r); no longer exist !*/ while ((post_len = ap_get_client_block( r, buf, HUGE_STRING_LEN )) > 0 ) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG,0, r, "GOT %d BYTES OF INPUT", post_len ); /* ap_reset_timeout(r); no longer exist !*/ WrapCStringLen( blockCS, buf, post_len ); append_cstring( &bufferCS, &blockCS ); } /* ap_kill_timeout(r); no longer exist !*/ } if( !CSLen(bufferCS) ) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "No XML-RPC request data received" ); free_cstring( &bufferCS ); return HTTP_INTERNAL_SERVER_ERROR; } /* Create a request buffer and populate it... */ if( (request = gwmc_create() ) == NULL ) { ap_log_rerror(APLOG_MARK, APLOG_ERR,0, r, "Failed to create request message" ); return HTTP_INTERNAL_SERVER_ERROR; } /* Add URI and request XML to buffer */ gwmc_add_data( request, DGF_REQ_URI, MIME_TEXT_PLAIN, URI, strlen(URI) ); gwmc_add_data( request, DGF_REQ_DATA, MIME_TEXT_PLAIN, CSStart(bufferCS), CSLen(bufferCS) ); free_cstring( &bufferCS ); /* Get data stream to send */ if( (stream = gwmc_get_message_ptr( request, &len )) == NULL ) { ap_log_rerror(APLOG_MARK, APLOG_ERR,0, r, "Failed to get message stream" ); CLEANUP_RESOURCES; return HTTP_INTERNAL_SERVER_ERROR; } if( ( ret = gw_svc_call( "/DGEE/SM/execXmlRpc", stream, len, &msg, 0 )) < 0 ){ ap_log_rerror(APLOG_MARK, APLOG_ERR,0, r, "gw_svc_call failed with code %d [%s]\n", gwerror, gw_errorstr(gwerror) ); CLEANUP_RESOURCES; switch( gwerror ) { case GWE_APPERR: /* Act on application errors */ /* Should have XML Fault Reply! */ break; case GWE_NOSVC: case GWE_SBLOCKD: return HTTP_SERVICE_UNAVAILABLE; default: return HTTP_INTERNAL_SERVER_ERROR; } } /* Instantiate a 'message buffer' from input data */ if( (reply = gwmc_importGWMessage( &msg )) == NULL ) { gw_logf( LOG_ERROR, "Could not instantiate request message buffer" ); CLEANUP_RESOURCES; ap_log_rerror(APLOG_MARK, APLOG_ERR,0, r, "Unable to get webservice reply" ); return HTTP_SERVICE_UNAVAILABLE; } ctype = MIME_TEXT_XML; xml = (char*)gwmc_read_data( reply, DGF_XMLRPC_REPLY, &ctype, 1, &len ); if( !xml || len == 0 ) { CLEANUP_RESOURCES; ap_log_rerror(APLOG_MARK, APLOG_ERR,0, r, "No XML returned" ); return HTTP_NOT_FOUND; } r->content_type = "text/xml"; sprintf( lenstr, "%ld", len ); apr_table_set(r->headers_out,"Content-Length", lenstr ); apr_table_set(r->headers_out,"X-DGEE-Server", "DotGNU/"DGVERSION";" ); /* ap_send_http_header(r); --> This function is not required any more */ ap_rwrite( xml, len, r ); CLEANUP_RESOURCES; /* gwmc_destroy( &request ); * gwmc_destroy( &reply ); */ gw_logf( LOG_INTDBG, "Apache mod_dgee client Exiting" ); return OK; /* NOT r->status, even if it has changed. */ } /* ------------------------------------------------------------------------- */ static int dgee_handler(request_rec *r) { if (strcmp(r->handler, "dgee-handler")) { return DECLINED; } switch( r->method_number ) { case M_OPTIONS: r->allowed |= (1 << M_GET); r->allowed |= (1 << M_POST); return DECLINED; case M_GET: return dgee_get_doc(r); case M_POST: return dgee_call_service(r); /*default:*/ } return HTTP_BAD_REQUEST; } static apr_status_t dgee_child_exit(void *data) { /* call the modified dgee_cleanup*/ server_rec *s = data; dgee_cleanup(s); return APR_SUCCESS; } static int dgee_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { /*call the modified dgee_init */ dgee_init( s, pconf ); return OK; } static int dgee_translate_handler(request_rec *r) { /* call uri2file */ return uri2file(r); } static void dgee_child_init(apr_pool_t *p, server_rec *s) { /* Just register dgee_child_exit */ apr_pool_cleanup_register(p, s, dgee_child_exit, dgee_child_exit); } static void register_dgee_hooks (apr_pool_t *p) { ap_hook_post_config(dgee_post_config,NULL, NULL,APR_HOOK_MIDDLE); ap_hook_child_init(dgee_child_init, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_handler(dgee_handler, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_translate_name(dgee_translate_handler, NULL, NULL, APR_HOOK_MIDDLE); } static const command_rec dgee_cmds[] = { AP_INIT_TAKE1("DGEEConfig", set_gwconfig, NULL, OR_OPTIONS, "DGEEConfig Full pathname of DotGNU Execution Environment config file" ), {NULL} }; module AP_MODULE_DECLARE_DATA dgee_module = { STANDARD20_MODULE_STUFF, NULL, /* dir config creater */ NULL, /* dir merger */ create_dgee_config, /* server config */ merge_dgee_config, /* merge server config */ dgee_cmds, /* command table */ register_dgee_hooks /* register hooks */ }; /* ------------------------------------------------------------------------- */ /* end */