| /* ---------------------------------------------------------------------------- |
| * mod_websh.c -- handler for websh applications for Apache-1.3 |
| * nca-073-9 |
| * |
| * Copyright (c) 1996-2000 by Netcetera AG. |
| * Copyright (c) 2001 by Apache Software Foundation. |
| * All rights reserved. |
| * |
| * See the file "license.terms" for information on usage and |
| * redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
| * |
| * @(#) $Id$ |
| * ------------------------------------------------------------------------- */ |
| |
| /* ==================================================================== |
| * Copyright (c) 1995-1999 The Apache Group. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. All advertising materials mentioning features or use of this |
| * software must display the following acknowledgment: |
| * "This product includes software developed by the Apache Group |
| * for use in the Apache HTTP server project (http://www.apache.org/)." |
| * |
| * 4. The names "Apache Server" and "Apache Group" must not be used to |
| * endorse or promote products derived from this software without |
| * prior written permission. For written permission, please contact |
| * apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache" |
| * nor may "Apache" appear in their names without prior written |
| * permission of the Apache Group. |
| * |
| * 6. Redistributions of any form whatsoever must retain the following |
| * acknowledgment: |
| * "This product includes software developed by the Apache Group |
| * for use in the Apache HTTP server project (http://www.apache.org/)." |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY |
| * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
| * OF THE POSSIBILITY OF SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Group and was originally based |
| * on software written by Netcetera AG, Zurich, Switzerland. |
| * For more information on the Apache Group and the Apache HTTP server |
| * project, please see <http://www.apache.org/>. |
| * |
| */ |
| |
| /* ---------------------------------------------------------------------------- |
| * tcl/websh includes |
| * ------------------------------------------------------------------------- */ |
| #include "tcl.h" /* tcl headers */ |
| #include "web.h" /* websh headers */ |
| #include "mod_websh.h" /* apache stuff */ |
| #include "interpool.h" |
| #include "logtoap.h" |
| |
| #define WEBSHHANDLER "websh" |
| |
| #ifndef APACHE2 |
| module MODULE_VAR_EXPORT websh_module; |
| #define APPOOL pool |
| #else /* APACHE2 */ |
| module AP_MODULE_DECLARE_DATA websh_module; |
| #define APPOOL apr_pool_t |
| #endif /* APACHE2 */ |
| |
| /* ============================================================================ |
| * httpd config and log handling |
| * ========================================================================= */ |
| |
| /* Configuration stuff */ |
| |
| #ifndef APACHE2 |
| static void cleanup_websh_pool(void *conf) |
| { |
| /* cleanup the pool when server is restarted (-HUP) */ |
| destroyPool((websh_server_conf *) conf); |
| } |
| #else /* APACHE2 */ |
| static apr_status_t cleanup_websh_pool(void *conf) |
| { |
| /* cleanup the pool when server is restarted (-HUP) */ |
| destroyPool((websh_server_conf *) conf); |
| return APR_SUCCESS; |
| } |
| #endif /* APACHE2 */ |
| |
| #ifndef APACHE2 |
| static void exit_websh_pool(server_rec * s, APPOOL * p) |
| { |
| websh_server_conf *conf = |
| (websh_server_conf *) ap_get_module_config(s->module_config, |
| &websh_module); |
| /* cleanup the pool when server is restarted (-HUP) */ |
| destroyPool(conf); |
| } |
| #else |
| static apr_status_t exit_websh_pool(void *data) |
| { |
| server_rec *s = data; |
| websh_server_conf *conf = |
| (websh_server_conf *) ap_get_module_config(s->module_config, |
| &websh_module); |
| /* cleanup the pool when server is restarted (-HUP) */ |
| destroyPool(conf); |
| return APR_SUCCESS; |
| } |
| #endif |
| |
| static void *create_websh_config(APPOOL * p, server_rec * s) |
| { |
| |
| websh_server_conf *c = |
| #ifndef APACHE2 |
| (websh_server_conf *) ap_palloc(p, sizeof(websh_server_conf)); |
| #else /* APACHE2 */ |
| (websh_server_conf *) apr_palloc(p, sizeof(websh_server_conf)); |
| #endif /* APACHE2 */ |
| c->scriptName = NULL; |
| c->mainInterp = NULL; |
| c->mainInterpLock = NULL; |
| c->webshPool = NULL; |
| c->webshPoolLock = NULL; |
| c->server = s; |
| |
| /* make sure we call cleanup the our websh pool when this memory is freed */ |
| #ifndef APACHE2 |
| ap_register_cleanup(p, (void *) c, cleanup_websh_pool, ap_null_cleanup); |
| #else /* APACHE2 */ |
| apr_pool_cleanup_register(p, (void *) c, cleanup_websh_pool, |
| apr_pool_cleanup_null); |
| #endif /* APACHE2 */ |
| |
| return c; |
| } |
| |
| static void *merge_websh_config(APPOOL * p, void *basev, void *overridesv) |
| { |
| /* fixme-later: is this correct? (reset the locks) */ |
| |
| /* When we have seperate interpreters for seperate virtual hosts, |
| * and things of that nature, then we can worry about this - |
| * davidw. */ |
| |
| /* ((websh_server_conf *) overridesv)->mainInterpLock = NULL; |
| ((websh_server_conf *) overridesv)->webshPoolLock = NULL; */ |
| return basev; |
| } |
| |
| static const char *set_webshscript(cmd_parms * cmd, void *dummy, const char *arg) |
| { |
| server_rec *s = cmd->server; |
| websh_server_conf *conf = |
| (websh_server_conf *) ap_get_module_config(s->module_config, |
| &websh_module); |
| #ifdef APACHE2 |
| conf->scriptName = ap_server_root_relative(cmd->pool, arg); |
| #else /* APACHE2 */ |
| conf->scriptName = ap_server_root_relative(cmd->pool, (char *) arg); |
| #endif |
| |
| return NULL; |
| } |
| |
| #ifdef APACHE2 |
| static void websh_init_child(apr_pool_t * p, server_rec * s) |
| { |
| /* here we create our main Interp and Pool */ |
| websh_server_conf *conf = |
| (websh_server_conf *) ap_get_module_config(s->module_config, |
| &websh_module); |
| if (!initPool(conf)) { |
| ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, |
| "Could not init interp pool"); |
| return; |
| } |
| apr_pool_cleanup_register(p, s, exit_websh_pool, exit_websh_pool); |
| } |
| |
| #else /* APACHE2 */ |
| static void websh_init_child(server_rec *s, pool *p) |
| { |
| /* here we create our main Interp and Pool */ |
| websh_server_conf *conf = |
| (websh_server_conf *) ap_get_module_config(s->module_config, |
| &websh_module); |
| if (!initPool(conf)) { |
| ap_log_error(APLOG_MARK, APLOG_ERR, s, |
| "Could not init interp pool"); |
| return; |
| } |
| } |
| #endif |
| |
| static const command_rec websh_cmds[] = { |
| {"WebshConfig", CMDFUNC set_webshscript, NULL, RSRC_CONF, TAKE1, |
| "the name of the main websh configuration file"}, |
| {NULL} |
| }; |
| |
| /* ---------------------------------------------------------------------------- |
| * run_websh_script |
| * ------------------------------------------------------------------------- */ |
| static int run_websh_script(request_rec * r) |
| { |
| |
| WebInterp *webInterp = NULL; |
| websh_server_conf *conf = |
| (websh_server_conf *) ap_get_module_config(r->server->module_config, |
| &websh_module); |
| |
| /* checkme: check type of timeout in MP case */ |
| /* ap_soft_timeout("!!! timeout for run_websh_script expired", r); */ |
| |
| #ifndef APACHE2 |
| |
| /* ap_log_printf(r->server,"mtime of %s: %ld",r->filename,r->finfo.st_mtime); */ |
| webInterp = poolGetWebInterp(conf, r->filename, r->finfo.st_mtime, r); |
| if (webInterp == NULL || webInterp->interp == NULL) { |
| ap_log_printf(r->server, "mod_websh - no interp!"); |
| return 0; |
| } |
| |
| #else /* APACHE2 */ |
| |
| /* ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, "mtime of %s: %ld",r->filename,r->finfo.mtime); */ |
| webInterp = poolGetWebInterp(conf, r->filename, (long) r->finfo.mtime, r); |
| /* ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, "got pool %p", webInterp); */ |
| if (webInterp == NULL || webInterp->interp == NULL) { |
| ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r, |
| "mod_websh - no interp!"); |
| return 0; |
| } |
| |
| #endif /* APACHE2 */ |
| |
| if (Tcl_InterpDeleted(webInterp->interp)) { |
| #ifndef APACHE2 |
| ap_log_printf(r->server, |
| "mod_websh - hey, somebody is deleting the interp!"); |
| #else /* APACHE2 */ |
| ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r, |
| "mod_websh - hey, somebody is deleting the interp!"); |
| #endif /* APACHE2 */ |
| return 0; |
| } |
| |
| Tcl_SetAssocData(webInterp->interp, WEB_AP_ASSOC_DATA, NULL, |
| (ClientData) r); |
| |
| Tcl_SetAssocData(webInterp->interp, WEB_INTERP_ASSOC_DATA, NULL, |
| (ClientData) webInterp); |
| |
| if (createApchannel(webInterp->interp, r) != TCL_OK) { |
| #ifndef APACHE2 |
| ap_log_printf(r->server, "mod_websh - cannot create apchannel"); |
| #else /* APACHE2 */ |
| ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r, |
| "mod_websh - cannot create apchannel"); |
| #endif /* APACHE2 */ |
| return 0; |
| } |
| |
| if (Tcl_Eval(webInterp->interp, "web::ap::perReqInit") != TCL_OK) { |
| #ifndef APACHE2 |
| ap_log_printf(r->server, |
| "mod_websh - cannot init per-request Websh code: %s", Tcl_GetStringResult(webInterp->interp)); |
| #else /* APACHE2 */ |
| ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r, |
| "mod_websh - cannot init per-request Websh code: %s", Tcl_GetStringResult(webInterp->interp)); |
| #endif /* APACHE2 */ |
| return 0; |
| } |
| |
| if (webInterp->code != NULL) { |
| int res = 0; |
| |
| Tcl_IncrRefCount(webInterp->code); |
| res = Tcl_EvalObjEx(webInterp->interp, webInterp->code, 0); |
| Tcl_DecrRefCount(webInterp->code); |
| |
| if (res != TCL_OK) { |
| |
| char *errorInfo = NULL; |
| errorInfo = |
| (char *) Tcl_GetVar(webInterp->interp, "errorInfo", TCL_GLOBAL_ONLY); |
| logToAp(webInterp->interp, NULL, errorInfo); |
| } |
| |
| Tcl_ResetResult(webInterp->interp); |
| } |
| |
| if (Tcl_Eval(webInterp->interp, "web::ap::perReqCleanup") != TCL_OK) { |
| #ifndef APACHE2 |
| ap_log_printf(r->server, "mod_websh - error while cleaning-up: %s", Tcl_GetStringResult(webInterp->interp)); |
| #else /* APACHE2 */ |
| ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r, |
| "mod_websh - error while cleaning-up: %s", Tcl_GetStringResult(webInterp->interp)); |
| #endif /* APACHE2 */ |
| return 0; |
| } |
| |
| if (destroyApchannel(webInterp->interp) != TCL_OK) { |
| #ifndef APACHE2 |
| ap_log_printf(r->server, "mod_websh - error closing ap-channel"); |
| #else /* APACHE2 */ |
| ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r, |
| "mod_websh - error closing ap-channel"); |
| #endif /* APACHE2 */ |
| return 0; |
| } |
| |
| Tcl_DeleteAssocData(webInterp->interp, WEB_AP_ASSOC_DATA); |
| Tcl_DeleteAssocData(webInterp->interp, WEB_INTERP_ASSOC_DATA); |
| |
| poolReleaseWebInterp(webInterp); |
| |
| /* ap_kill_timeout(r); */ |
| |
| return 1; |
| } |
| |
| /* ---------------------------------------------------------------------------- |
| * websh_handler |
| * ------------------------------------------------------------------------- */ |
| |
| static int websh_handler(request_rec * r) |
| { |
| |
| int res; |
| |
| #ifdef APACHE2 |
| if (strcmp(r->handler, WEBSHHANDLER)) |
| return DECLINED; |
| #endif /* APACHE2 */ |
| |
| /* We don't check to see if the file exists, because it might be |
| * mapped with web::interpmap. */ |
| |
| if ((res = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) |
| return res; |
| |
| /* SERVER_SIGNATURE, REMOTE_PORT, .... */ |
| ap_add_common_vars(r); |
| |
| /* GATEWAY_INTERFACE, SERVER_PROTOCOL, ... */ |
| ap_add_cgi_vars(r); |
| |
| #ifdef CHARSET_EBCDIC |
| ap_bsetflag(r->connection->client, B_EBCDIC2ASCII, 1); |
| #endif /*CHARSET_EBCDIC */ |
| |
| /* --------------------------------------------------------------------- |
| * ready to rumble |
| * --------------------------------------------------------------------- */ |
| if (!run_websh_script(r)) { |
| #ifndef APACHE2 |
| ap_log_rerror(APLOG_MARK, APLOG_ERR, r, |
| "couldn't run websh script: %s", |
| r->filename); |
| #else /* APACHE2 */ |
| ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r, |
| "couldn't run websh script: %s", |
| r->filename); |
| #endif /* APACHE2 */ |
| return HTTP_INTERNAL_SERVER_ERROR; |
| } |
| |
| return OK; /* NOT r->status, even if it has changed. */ |
| } |
| |
| #ifndef APACHE2 |
| |
| static const handler_rec websh_handlers[] = { |
| {WEBSHHANDLER, websh_handler}, |
| {NULL} |
| }; |
| |
| module MODULE_VAR_EXPORT websh_module = { |
| STANDARD_MODULE_STUFF, |
| NULL, /* initializer */ |
| NULL, /* dir config creater */ |
| NULL, /* dir merger --- default is to override */ |
| create_websh_config, /* server config */ |
| merge_websh_config, /* merge server config */ |
| websh_cmds, /* command table */ |
| websh_handlers, /* handlers */ |
| NULL, /* filename translation */ |
| NULL, /* check_user_id */ |
| NULL, /* check auth */ |
| NULL, /* check access */ |
| NULL, /* type_checker */ |
| NULL, /* fixups */ |
| NULL, /* logger */ |
| NULL, /* header parser */ |
| websh_init_child, /* child_init */ |
| exit_websh_pool, /* child_exit */ |
| NULL /* post read-request */ |
| }; |
| |
| #else /* APACHE2 */ |
| |
| static void register_websh_hooks(apr_pool_t *p) { |
| ap_hook_handler(websh_handler, NULL, NULL, APR_HOOK_MIDDLE); |
| |
| ap_hook_child_init(websh_init_child, NULL, NULL, APR_HOOK_MIDDLE); |
| } |
| |
| module AP_MODULE_DECLARE_DATA websh_module = { |
| STANDARD20_MODULE_STUFF, |
| NULL, /* dir config creater */ |
| NULL, /* dir merger --- default is to override */ |
| create_websh_config, /* server config */ |
| merge_websh_config, /* merge server config */ |
| websh_cmds, /* command table */ |
| register_websh_hooks /* register hooks */ |
| }; |
| |
| #endif /* APACHE2 */ |