--- parser3/src/targets/apache13/Attic/mod_parser3.C 2001/10/11 08:29:21 1.1 +++ parser3/src/targets/apache13/Attic/mod_parser3.C 2003/07/23 08:18:17 1.28.2.6.2.6 @@ -1,12 +1,18 @@ /** @file Parser: apache 1.3 module. - Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com) - Author: Alexander Petrosyan (http://design.ru/paf) - - $Id: mod_parser3.C,v 1.1 2001/10/11 08:29:21 parser Exp $ + Copyright (c) 2001-2003 ArtLebedev Group (http://www.artlebedev.com) + Author: Alexandr Petrosian (http://paf.design.ru) */ +static const char* IDENT_MOD_PARSER3_C="$Date: 2003/07/23 08:18:17 $"; + +#if _MSC_VER +#pragma warning(disable:4518) +#endif + +#include "pa_config_includes.h" + #include "httpd.h" #include "http_config.h" #include "http_core.h" @@ -15,76 +21,49 @@ #include "http_protocol.h" #include "util_script.h" +#include "pa_globals.h" + +#include "pa_common.h" #include "pa_sapi.h" #include "classes.h" -#include "pa_common.h" -#include "pa_globals.h" #include "pa_request.h" #include "pa_version.h" #include "pa_socks.h" -#ifdef _DEBUG -# define DEBUG_PREFIX "debug_" -# define PARSER3_MODULE debug_parser3_module -#else -# define DEBUG_PREFIX -# define PARSER3_MODULE parser3_module -#endif - -// consts - -extern const char *main_RCSIds[]; -#ifdef USE_SMTP -extern const char *smtp_RCSIds[]; -#endif -extern const char *gd_RCSIds[]; -extern const char *classes_RCSIds[]; -extern const char *types_RCSIds[]; -extern const char *ApacheModuleParser3_RCSIds[]; -#ifdef XML -extern const char *xalan_patched_RCSIds[]; -#endif -const char **RCSIds[]={ - main_RCSIds, -#ifdef USE_SMTP - smtp_RCSIds, -#endif - gd_RCSIds, - classes_RCSIds, - types_RCSIds, - ApacheModuleParser3_RCSIds, -#ifdef XML - xalan_patched_RCSIds, -#endif - 0 -}; - /// apache parser module configuration [httpd.conf + .htaccess-es] struct Parser_module_config { - const char* parser_root_config_filespec; ///< filespec of admin's config file - const char* parser_site_config_filespec; ///< filespec of site's config file + const char* parser_config_filespec; ///< filespec of site's config file + bool parser_status_allowed; }; /* * Declare ourselves so the configuration routines can find and know us. * We'll fill it in at the end of the module. */ -extern "C" module MODULE_VAR_EXPORT PARSER3_MODULE; +extern "C" module MODULE_VAR_EXPORT parser3_module; /* * Locate our directory configuration record for the current request. */ static Parser_module_config *our_dconfig(request_rec *r) { return (Parser_module_config *) - ap_get_module_config(r->per_dir_config, &PARSER3_MODULE); + ap_get_module_config(r->per_dir_config, &parser3_module); } -static const char *cmd_parser_config(cmd_parms *cmd, void *mconfig, char *file_spec) { +static const char* cmd_parser_config(cmd_parms *cmd, void *mconfig, char *file_spec) { Parser_module_config *cfg = (Parser_module_config *) mconfig; // remember assigned filespec into cfg - (cmd->info?cfg->parser_root_config_filespec:cfg->parser_site_config_filespec)=file_spec; + cfg->parser_config_filespec=file_spec; + + return NULL; +} +static const char* cmd_parser_status_allowed(cmd_parms *cmd, void *mconfig, char *file_spec) { + //_asm int 3; + Parser_module_config *cfg = (Parser_module_config *) mconfig; + + cfg->parser_status_allowed=true; return NULL; } @@ -118,42 +97,97 @@ static const char *cmd_parser_config(cmd //@{ /// SAPI func decl -void SAPI::log(Pool& pool, const char *fmt, ...) { - request_rec *r=static_cast(pool.context()); - va_list args; - va_start(args,fmt); +class SAPI_Info { +public: + request_rec* r; +}; + +void SAPI::log(SAPI_Info& SAPI_info, const char* fmt, ...) { + va_list args; + va_start(args,fmt); + char buf[MAX_STRING]; + size_t size=vsnprintf(buf, MAX_STRING, fmt, args); + remove_crlf(buf, buf+size); + ap_log_rerror(0, 0, APLOG_ERR | APLOG_NOERRNO, SAPI_info.r, "%s", buf); + va_end(args); +} + +static void die_or_abort(const char* fmt, va_list args, bool write_core) { char buf[MAX_STRING]; size_t size=vsnprintf(buf, MAX_STRING, fmt, args); remove_crlf(buf, buf+size); - ap_log_rerror(0, 0, APLOG_ERR | APLOG_NOERRNO, r, "%s", buf); - va_end(args); + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, "%s", buf); + + // exit & try to produce core dump + if(write_core) + abort(); + else + exit(1); +} + +void SAPI::die(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + die_or_abort(fmt, args, false/*write core?*/); + va_end(args); } -const char *SAPI::get_env(Pool& pool, const char *name) { - request_rec *r=static_cast(pool.context()); - return (const char *)ap_table_get(r->subprocess_env, name); +void SAPI::abort(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + die_or_abort(fmt, args, true/*write core?*/); + va_end(args); } -size_t SAPI::read_post(Pool& pool, char *buf, size_t max_bytes) { - request_rec *r=static_cast(pool.context()); +char* SAPI::get_env(SAPI_Info& SAPI_info, const char* name) { + const char* dont_return_me=(const char* )ap_table_get(SAPI_info.r->subprocess_env, name); + return dont_return_me?pa_strdup(dont_return_me):0; +} -/* ap_log_error(APLOG_MARK, APLOG_DEBUG, r->server, +#ifndef DOXYGEN +struct SAPI_environment_append_info { + const char** cur; +}; +#endif +static const char* mk_env_pair(const char* key, const char* value) { + char *result=new(PointerFreeGC) char[strlen(key)+1/*=*/+strlen(value)+1/*0*/]; + strcpy(result, key); strcat(result, "="); strcat(result, value); + return result; +} +static int SAPI_environment_append(void *d, const char* k, const char* val) { + if( k && val ) { + SAPI_environment_append_info& info= + *static_cast(d); + *info.cur++=mk_env_pair(k, val); + } + return 1/*true*/; +} +const char* const* SAPI::environment(SAPI_Info& SAPI_info) { + const table *t=SAPI_info.r->subprocess_env; + const char** result=new const char*[ap_table_elts(t)->nelts+1/*0*/]; + SAPI_environment_append_info info={result}; + ap_table_do(SAPI_environment_append, &info, t, 0); *info.cur=0; // mark EOE + return result; +} + +size_t SAPI::read_post(SAPI_Info& SAPI_info, char *buf, size_t max_bytes) { +/* ap_log_error(APLOG_MARK, APLOG_DEBUG, SAPI_info.r->server, "mod_parser3: SAPI::read_post(max=%u)", max_bytes); */ int retval; - if((retval = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) + if((retval = ap_setup_client_block(SAPI_info.r, REQUEST_CHUNKED_ERROR))) return 0; - if(!ap_should_client_block(r)) + if(!ap_should_client_block(SAPI_info.r)) return 0; uint total_read_bytes=0; void (*handler)(int)=signal(SIGPIPE, SIG_IGN); while (total_read_bytes(pool.context()); - - if(strcasecmp(key, "location")==0) - r->status=302; +/// @test location provide with protocol. think about internal redirects +void SAPI::add_header_attribute(SAPI_Info& SAPI_info, + const char* dont_store_key, const char* dont_store_value) { + if(strcasecmp(dont_store_key, "location")==0) + SAPI_info.r->status=302; - if(strcasecmp(key, "content-type")==0) { + if(strcasecmp(dont_store_key, "content-type")==0) { /* r->content_type, *not* r->headers_out("Content-type"). If you don't * set it, it will be filled in with the server's default type (typically * "text/plain"). You *must* also ensure that r->content_type is lower * case. */ - r->content_type = value; - } else if(strcasecmp(key, "status")==0) - r->status=atoi(value); + SAPI_info.r->content_type = ap_pstrdup(SAPI_info.r->pool, dont_store_value); + } else if(strcasecmp(dont_store_key, "status")==0) + SAPI_info.r->status=atoi(dont_store_value); else - ap_table_addn(r->headers_out, key, value); + ap_table_addn(SAPI_info.r->headers_out, + ap_pstrdup(SAPI_info.r->pool, dont_store_key), + ap_pstrdup(SAPI_info.r->pool, dont_store_value)); } -void SAPI::send_header(Pool& pool) { - request_rec *r=static_cast(pool.context()); - - ap_hard_timeout("Send header", r); - ap_send_http_header(r); - ap_kill_timeout(r); +void SAPI::send_header(SAPI_Info& SAPI_info) { + ap_hard_timeout("Send header", SAPI_info.r); + ap_send_http_header(SAPI_info.r); + ap_kill_timeout(SAPI_info.r); } -void SAPI::send_body(Pool& pool, const void *buf, size_t size) { - request_rec *r=static_cast(pool.context()); - - ap_hard_timeout("Send body", r); - ap_rwrite(buf, size, r); - ap_kill_timeout(r); +void SAPI::send_body(SAPI_Info& SAPI_info, const void *buf, size_t size) { + ap_hard_timeout("Send body", SAPI_info.r); + ap_rwrite(buf, size, SAPI_info.r); + ap_kill_timeout(SAPI_info.r); } //@} @@ -204,83 +236,110 @@ void SAPI::send_body(Pool& pool, const v @todo intelligent cache-control */ -static int parser_handler(request_rec *r) { -// _asm int 3; - if(r->finfo.st_mode == 0) - return NOT_FOUND; +static void real_parser_handler(SAPI_Info& SAPI_info) { + ap_add_common_vars(SAPI_info.r); + ap_add_cgi_vars(SAPI_info.r); + + // Request info + Request_info request_info; memset(&request_info, 0, sizeof(request_info)); + + request_info.document_root=SAPI::get_env(SAPI_info, "DOCUMENT_ROOT"); + request_info.path_translated=SAPI_info.r->filename; + request_info.method=SAPI_info.r->method; + request_info.query_string=SAPI_info.r->args; + request_info.uri=SAPI::get_env(SAPI_info, "REQUEST_URI"); + request_info.content_type=SAPI::get_env(SAPI_info, "CONTENT_TYPE"); + const char* content_length=SAPI::get_env(SAPI_info, "CONTENT_LENGTH"); + request_info.content_length=content_length?atoi(content_length):0; + request_info.cookie=SAPI::get_env(SAPI_info, "HTTP_COOKIE"); + request_info.mail_received=false; + + // config + Parser_module_config *dcfg=our_dconfig(SAPI_info.r); + + //_asm int 3; + // prepare to process request + Request request( + SAPI_info, + request_info, + String::Language(String::L_HTML|String::L_OPTIMIZE_BIT), + dcfg->parser_status_allowed + ); - Pool pool(r->pool); - pool.set_context(r); + // process the request + request.core( + dcfg->parser_config_filespec, true, // /path/to/config + SAPI_info.r->header_only!=0); +} - Parser_module_config *dcfg=our_dconfig(r); +void call_real_parser_handler__do_SEH(SAPI_Info& SAPI_info) { +#if _MSC_VER & !defined(_DEBUG) + LPEXCEPTION_POINTERS system_exception=0; + __try { +#endif + real_parser_handler(SAPI_info); + +#if _MSC_VER & !defined(_DEBUG) + } __except ( + (system_exception=GetExceptionInformation()), + EXCEPTION_EXECUTE_HANDLER) { + + if(system_exception) + if(_EXCEPTION_RECORD *er=system_exception->ExceptionRecord) + throw Exception(0, + 0, + "Exception 0x%08X at 0x%08X", er->ExceptionCode, er->ExceptionAddress); + else + throw Exception(0, 0, "Exception "); + else + throw Exception(0, 0, "Exception "); + } +#endif +} +/// @test r->finfo.st_mode check seems to work only on win32 +static int parser_handler(request_rec *r) { + // SAPI info + SAPI_Info SAPI_info; SAPI_info.r=r; + //_asm int 3; + if(r->finfo.st_mode == 0) + return NOT_FOUND; + /* A flag which modules can set, to indicate that the data being * returned is volatile, and clients should be told not to cache it. */ - r->no_cache=1; - - PTRY { // global try - ap_add_common_vars(r); - ap_add_cgi_vars(r); - - // Request info - Request::Info request_info; - request_info.document_root=SAPI::get_env(pool, "DOCUMENT_ROOT"); - request_info.path_translated=r->filename; - request_info.method=r->method; - request_info.query_string=r->args; - request_info.uri=SAPI::get_env(pool, "REQUEST_URI"); - request_info.content_type=SAPI::get_env(pool, "CONTENT_TYPE"); - const char *content_length=SAPI::get_env(pool, "CONTENT_LENGTH"); - request_info.content_length=content_length?atoi(content_length):0; - request_info.cookie=SAPI::get_env(pool, "HTTP_COOKIE"); - request_info.user_agent=SAPI::get_env(pool, "HTTP_USER_AGENT"); - - //_asm int 3; - // prepare to process request - Request request(pool, - request_info, - String::UL_USER_HTML - ); - - // process the request - request.core( - dcfg->parser_root_config_filespec, true, // /path/to/admin/config - dcfg->parser_site_config_filespec, true, // /path/to/site/config - r->header_only!=0); - // no actions with request' data past this point - // request.exception not not handled here, but all - // request' data are associated with it's pool=exception +// r->no_cache=1; + try { // global try + call_real_parser_handler__do_SEH(SAPI_info); // successful finish - } PCATCH(e) { // global problem + } catch(const Exception& e) { // global problem // don't allocate anything on pool here: // possible pool' exception not catch-ed now // and there could be out-of-memory exception - const char *body=e.comment(); + const char* body=e.comment(); // log it - SAPI::log(pool, "exception in request exception handler: %s", body); + SAPI::log(SAPI_info, "exception in request exception handler: %s", body); // int content_length=strlen(body); // prepare header - SAPI::add_header_attribute(pool, "content-type", "text/plain"); + SAPI::add_header_attribute(SAPI_info, "content-type", "text/plain"); char content_length_cstr[MAX_NUMBER]; snprintf(content_length_cstr, MAX_NUMBER, "%u", content_length); - SAPI::add_header_attribute(pool, "content-length", content_length_cstr); + SAPI::add_header_attribute(SAPI_info, "content-length", content_length_cstr); // send header - SAPI::send_header(pool); + SAPI::send_header(SAPI_info); // send body if(!r->header_only) - SAPI::send_body(pool, body, content_length); + SAPI::send_body(SAPI_info, body, content_length); // unsuccessful finish } - PEND_CATCH /* * We did what we wanted to do, so tell the rest of the server we @@ -332,24 +391,16 @@ static void setup_module_cells() { return; globals_inited=true; - /* - * allocate our module-private pool. - */ - static Pool pool(ap_make_sub_pool(NULL)); // global pool - PTRY { + /// no trying to __try here [yet] + try { // init socks - init_socks(pool); + pa_init_socks(); - // init global classes - init_methoded_array(pool); // init global variables - pa_globals_init(pool); - } PCATCH(e) { // global problem - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, - "setup_module_cells failed: ", e.comment()); - exit(1); + pa_globals_init(); + } catch(const Exception& e) { // global problem + SAPI::abort("setup_module_cells failed: %s", e.comment()); } - PEND_CATCH } static void parser_server_init(server_rec *s, pool *p) { @@ -376,6 +427,7 @@ static void parser_server_init(server_re * structure. */ static void *parser_create_dir_config(pool *p, char *dirspec) { + //_asm int 3; /* * Allocate the space for our record from the pool supplied. */ @@ -385,8 +437,7 @@ static void *parser_create_dir_config(po * Now fill in the defaults. If there are any `parent' configuration * records, they'll get merged as part of a separate callback. */ - cfg->parser_root_config_filespec = 0; - cfg->parser_site_config_filespec = 0; + return (void *) cfg; } @@ -404,22 +455,29 @@ static void *parser_create_dir_config(po * * The return value is a pointer to the created module-specific structure * containing the merged values. + + 20011126 paf: noticed, that this is called even on virtual root merge with something "parent", + while thought that that is part of merge_server... + */ static void *parser_merge_dir_config(pool *p, void *parent_conf, void *newloc_conf) { + //_asm int 3; Parser_module_config *merged_config = (Parser_module_config *) ap_pcalloc(p, sizeof(Parser_module_config)); Parser_module_config *pconf = (Parser_module_config *) parent_conf; Parser_module_config *nconf = (Parser_module_config *) newloc_conf; - // always from parent - merged_config->parser_root_config_filespec = ap_pstrdup(p, pconf->parser_root_config_filespec); - /* + merged_config->parser_config_filespec = ap_pstrdup(p, nconf->parser_config_filespec? + nconf->parser_config_filespec:pconf->parser_config_filespec); + merged_config->parser_status_allowed= + pconf->parser_status_allowed || + nconf->parser_status_allowed; + + /* * Some things get copied directly from the more-specific record, rather * than getting merged. */ - merged_config->parser_site_config_filespec = ap_pstrdup(p, nconf->parser_site_config_filespec? - nconf->parser_site_config_filespec:pconf->parser_site_config_filespec); return (void *) merged_config; } @@ -432,16 +490,14 @@ static void *parser_merge_dir_config(poo * structure. */ static void *parser_create_server_config(pool *p, server_rec *s) { + //_asm int 3; /* - * As with the parser_create_dir_config() reoutine, we allocate and fill + * As with the parser_create_dir_config() routine, we allocate and fill * in an empty record. */ Parser_module_config *cfg= (Parser_module_config *) ap_pcalloc(p, sizeof(Parser_module_config)); - cfg->parser_root_config_filespec = 0; - cfg->parser_site_config_filespec = 0; - return (void *) cfg; } @@ -461,6 +517,7 @@ static void *parser_create_server_config static void *parser_merge_server_config(pool *p, void *server1_conf, void *server2_conf) { + //_asm int 3; Parser_module_config *merged_config = (Parser_module_config *) ap_pcalloc(p, sizeof(Parser_module_config)); @@ -471,10 +528,11 @@ static void *parser_merge_server_config( * Our inheritance rules are our own, and part of our module's semantics. * Basically, just note whence we came. */ - merged_config->parser_root_config_filespec = ap_pstrdup(p, s2conf->parser_root_config_filespec? - s2conf->parser_root_config_filespec:s1conf->parser_root_config_filespec); - merged_config->parser_site_config_filespec = ap_pstrdup(p, s2conf->parser_site_config_filespec? - s2conf->parser_site_config_filespec:s1conf->parser_site_config_filespec); + merged_config->parser_config_filespec = ap_pstrdup(p, s2conf->parser_config_filespec? + s2conf->parser_config_filespec:s1conf->parser_config_filespec); + merged_config->parser_status_allowed= + s1conf->parser_status_allowed || + s2conf->parser_status_allowed; return (void *) merged_config; } @@ -551,21 +609,21 @@ static int parser_access_checker(request static const command_rec parser_cmds[] = { { - DEBUG_PREFIX"ParserRootConfig", /* directive name */ - (const char *(*)(void))((void *)cmd_parser_config), // config action routine - (void*)true, /* argument to include in call */ - (int)(ACCESS_CONF|RSRC_CONF), /* where available */ - TAKE1, /* arguments */ - "Parser root config filespec (Admin)" // directive description - }, - { - DEBUG_PREFIX"ParserSiteConfig", /* directive name */ - (const char *(*)(void))((void *)cmd_parser_config), // config action routine - (void*)false, /* argument to include in call */ + "ParserConfig", /* directive name */ + (const char* (*)(void))((void *)cmd_parser_config), // config action routine + (void*)0, /* argument to include in call */ (int)(OR_OPTIONS), /* where available */ TAKE1, /* arguments */ - "Parser site config filespec" // directive description + "Parser config filespec" // directive description }, + { + "ParserStatusAllowed", /* directive name */ + (const char* (*)(void))((void *)cmd_parser_status_allowed), // config action routine + (void*)0, /* argument to include in call */ + (int)(ACCESS_CONF), /* where available */ + NO_ARGS, /* arguments */ + "Parser status class can be used" // directive description + }, {NULL} }; @@ -588,7 +646,7 @@ static const command_rec parser_cmds[] = */ static const handler_rec parser_handlers[] = { - {DEBUG_PREFIX"parser3-handler", parser_handler}, + {"parser3-handler", parser_handler}, {NULL} }; @@ -606,7 +664,7 @@ static const handler_rec parser_handlers * during request processing. Note that not all routines are necessarily * called (such as if a resource doesn't have access restrictions). */ -module MODULE_VAR_EXPORT PARSER3_MODULE = +module MODULE_VAR_EXPORT parser3_module = { STANDARD_MODULE_STUFF, parser_server_init, /* module initializer */ @@ -626,7 +684,7 @@ module MODULE_VAR_EXPORT PARSER3_MODULE }; #if defined(_MSC_VER) -# define APACHE_WIN32_SRC "/parser3project/win32apache13/src" +# define APACHE_WIN32_SRC "/parser3project/win32/apache13/src" # ifdef _DEBUG # pragma comment(lib, APACHE_WIN32_SRC "/CoreD/ApacheCore.lib") # else