|
|
| version 1.19, 2002/03/27 15:30:37 | version 1.28.2.6.2.2, 2003/03/20 08:11:15 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: apache 1.3 module. | Parser: apache 1.3 module. |
| Copyright (c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com) | Copyright (c) 2001-2003 ArtLebedev Group (http://www.artlebedev.com) |
| Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) | Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) |
| $Id$ | |
| */ | */ |
| #include "pa_config_includes.h" | static const char* IDENT_MOD_PARSER3_C="$Date$"; |
| #if _MSC_VER | #include "pa_config_includes.h" |
| # include <new.h> | |
| #endif | |
| #include "pa_globals.h" | #include "pa_globals.h" |
| Line 30 | Line 26 |
| #include "pa_version.h" | #include "pa_version.h" |
| #include "pa_socks.h" | #include "pa_socks.h" |
| // 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[]; | |
| const char **RCSIds[]={ | |
| main_RCSIds, | |
| #ifdef USE_SMTP | |
| smtp_RCSIds, | |
| #endif | |
| gd_RCSIds, | |
| classes_RCSIds, | |
| types_RCSIds, | |
| ApacheModuleParser3_RCSIds, | |
| 0 | |
| }; | |
| /// apache parser module configuration [httpd.conf + .htaccess-es] | /// apache parser module configuration [httpd.conf + .htaccess-es] |
| struct Parser_module_config { | struct Parser_module_config { |
| const char* parser_root_config_filespec; ///< filespec of admin's config file | const char* parser_config_filespec; ///< filespec of site's config file |
| const char* parser_site_config_filespec; ///< filespec of site's config file | |
| bool parser_status_allowed; | bool parser_status_allowed; |
| }; | }; |
| Line 75 static Parser_module_config *our_dconfig | Line 46 static Parser_module_config *our_dconfig |
| 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; | Parser_module_config *cfg = (Parser_module_config *) mconfig; |
| // remember assigned filespec into cfg | // 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; | return NULL; |
| } | } |
| static const char *cmd_parser_status_allowed(cmd_parms *cmd, void *mconfig, char *file_spec) { | static const char* cmd_parser_status_allowed(cmd_parms *cmd, void *mconfig, char *file_spec) { |
| //_asm int 3; | //_asm int 3; |
| Parser_module_config *cfg = (Parser_module_config *) mconfig; | Parser_module_config *cfg = (Parser_module_config *) mconfig; |
| Line 121 static const char *cmd_parser_status_all | Line 92 static const char *cmd_parser_status_all |
| //@{ | //@{ |
| /// SAPI func decl | /// SAPI func decl |
| void SAPI::log(Pool& pool, const char *fmt, ...) { | void SAPI::logconst char* fmt, ...) { |
| request_rec *r=static_cast<request_rec *>(pool.get_context()); | request_rec *r=static_cast<request_rec *>(pool.get_context()); |
| va_list args; | va_list args; |
| Line 133 void SAPI::log(Pool& pool, const char *f | Line 104 void SAPI::log(Pool& pool, const char *f |
| va_end(args); | va_end(args); |
| } | } |
| void SAPI::die(const char *fmt, ...) { | static void die_or_abort(const char* fmt, va_list args, bool write_core) { |
| va_list args; | |
| va_start(args,fmt); | |
| char buf[MAX_STRING]; | char buf[MAX_STRING]; |
| size_t size=vsnprintf(buf, MAX_STRING, fmt, args); | size_t size=vsnprintf(buf, MAX_STRING, fmt, args); |
| remove_crlf(buf, buf+size); | remove_crlf(buf, buf+size); |
| ap_log_error(APLOG_MARK, APLOG_EMERG, 0, "%s", buf); | ap_log_error(APLOG_MARK, APLOG_EMERG, 0, "%s", buf); |
| va_end(args); | |
| exit(1); | // 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); | |
| } | |
| void SAPI::abort(const char* fmt, ...) { | |
| va_list args; | |
| va_start(args, fmt); | |
| die_or_abort(fmt, args, true/*write core?*/); | |
| va_end(args); | |
| } | |
| char* SAPI::get_env(SAPI_Info& info, const char* name) { | |
| request_rec *r=static_cast<request_rec *>(pool.get_context()); | |
| return (const char* )ap_table_get(r->subprocess_env, name); | |
| } | } |
| const char *SAPI::get_env(Pool& pool, const char *name) { | #ifndef DOXYGEN |
| struct SAPI_environment_append_info { | |
| ; | |
| const char* *cur; | |
| }; | |
| #endif | |
| static const char* mk_env_pairconst char* key, const char* value) { | |
| char *result=new 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<SAPI_environment_append_info *>(d); | |
| *info.cur++=mk_env_pair(*info.k, val); | |
| } | |
| return 1/*true*/; | |
| } | |
| const char* const *SAPI::environment(SAPI_Info& info, ) { | |
| request_rec *r=static_cast<request_rec *>(pool.get_context()); | request_rec *r=static_cast<request_rec *>(pool.get_context()); |
| return (const char *)ap_table_get(r->subprocess_env, name); | const table *t=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(Pool& pool, char *buf, size_t max_bytes) { | size_t SAPI::read_postchar *buf, size_t max_bytes) { |
| request_rec *r=static_cast<request_rec *>(pool.get_context()); | request_rec *r=static_cast<request_rec *>(pool.get_context()); |
| /* ap_log_error(APLOG_MARK, APLOG_DEBUG, r->server, | /* ap_log_error(APLOG_MARK, APLOG_DEBUG, r->server, |
| Line 178 size_t SAPI::read_post(Pool& pool, char | Line 192 size_t SAPI::read_post(Pool& pool, char |
| } | } |
| /// @test location provide with protocol. think about internal redirects | /// @test location provide with protocol. think about internal redirects |
| void SAPI::add_header_attribute(Pool& pool, const char *key, const char *value) { | void SAPI::add_header_attribute |
| const char* dont_store_key, const char* dont_store_value) { | |
| request_rec *r=static_cast<request_rec *>(pool.get_context()); | request_rec *r=static_cast<request_rec *>(pool.get_context()); |
| if(strcasecmp(key, "location")==0) | if(strcasecmp(key, "location")==0) |
| Line 194 void SAPI::add_header_attribute(Pool& po | Line 209 void SAPI::add_header_attribute(Pool& po |
| } else if(strcasecmp(key, "status")==0) | } else if(strcasecmp(key, "status")==0) |
| r->status=atoi(value); | r->status=atoi(value); |
| else | else |
| todo: copy dont_store_ to nonvilotile | |
| ap_table_addn(r->headers_out, key, value); | ap_table_addn(r->headers_out, key, value); |
| } | } |
| void SAPI::send_header(Pool& pool) { | void SAPI::send_header() { |
| request_rec *r=static_cast<request_rec *>(pool.get_context()); | request_rec *r=static_cast<request_rec *>(pool.get_context()); |
| ap_hard_timeout("Send header", r); | ap_hard_timeout("Send header", r); |
| Line 205 void SAPI::send_header(Pool& pool) { | Line 221 void SAPI::send_header(Pool& pool) { |
| ap_kill_timeout(r); | ap_kill_timeout(r); |
| } | } |
| void SAPI::send_body(Pool& pool, const void *buf, size_t size) { | void SAPI::send_bodyconst void *buf, size_t size) { |
| request_rec *r=static_cast<request_rec *>(pool.get_context()); | request_rec *r=static_cast<request_rec *>(pool.get_context()); |
| ap_hard_timeout("Send body", r); | ap_hard_timeout("Send body", r); |
| Line 220 void SAPI::send_body(Pool& pool, const v | Line 236 void SAPI::send_body(Pool& pool, const v |
| @todo intelligent cache-control | @todo intelligent cache-control |
| */ | */ |
| static void real_parser_handler(Pool& pool, request_rec *r) { | static void real_parser_handlerrequest_rec *r) { |
| ap_add_common_vars(r); | ap_add_common_vars(r); |
| ap_add_cgi_vars(r); | ap_add_cgi_vars(r); |
| // Request info | // Request info |
| Request::Info request_info; | Request::Info request_info; |
| request_info.document_root=SAPI::get_env(pool, "DOCUMENT_ROOT"); | request_info.document_root=SAPI::get_env("DOCUMENT_ROOT"); |
| request_info.path_translated=r->filename; | request_info.path_translated=r->filename; |
| request_info.method=r->method; | request_info.method=r->method; |
| request_info.query_string=r->args; | request_info.query_string=r->args; |
| request_info.uri=SAPI::get_env(pool, "REQUEST_URI"); | request_info.uri=SAPI::get_env("REQUEST_URI"); |
| request_info.content_type=SAPI::get_env(pool, "CONTENT_TYPE"); | request_info.content_type=SAPI::get_env("CONTENT_TYPE"); |
| const char *content_length=SAPI::get_env(pool, "CONTENT_LENGTH"); | const char* content_length=SAPI::get_env("CONTENT_LENGTH"); |
| request_info.content_length=content_length?atoi(content_length):0; | request_info.content_length=content_length?atoi(content_length):0; |
| request_info.cookie=SAPI::get_env(pool, "HTTP_COOKIE"); | request_info.cookie=SAPI::get_env("HTTP_COOKIE"); |
| request_info.user_agent=SAPI::get_env(pool, "HTTP_USER_AGENT"); | request_info.mail_received=false; |
| // config | // config |
| Parser_module_config *dcfg=our_dconfig(r); | Parser_module_config *dcfg=our_dconfig(r); |
| Line 250 static void real_parser_handler(Pool& po | Line 266 static void real_parser_handler(Pool& po |
| // process the request | // process the request |
| request.core( | request.core( |
| dcfg->parser_root_config_filespec, true, // /path/to/admin/config | dcfg->parser_config_filespec, true, // /path/to/config |
| dcfg->parser_site_config_filespec, true, // /path/to/site/config | |
| r->header_only!=0); | r->header_only!=0); |
| } | } |
| void call_real_parser_handler__do_SEH(Pool& pool, request_rec *r) { | void call_real_parser_handler__do_SEHrequest_rec *r) { |
| #if _MSC_VER & !defined(_DEBUG) | #if _MSC_VER & !defined(_DEBUG) |
| LPEXCEPTION_POINTERS system_exception=0; | LPEXCEPTION_POINTERS system_exception=0; |
| __try { | __try { |
| #endif | #endif |
| real_parser_handler(pool, r); | real_parser_handler(r); |
| #if _MSC_VER & !defined(_DEBUG) | #if _MSC_VER & !defined(_DEBUG) |
| } __except ( | } __except ( |
| Line 295 static int parser_handler(request_rec *r | Line 310 static int parser_handler(request_rec *r |
| // r->no_cache=1; | // r->no_cache=1; |
| try { // global try | try { // global try |
| call_real_parser_handler__do_SEH(pool, r); | call_real_parser_handler__do_SEH(r); |
| // successful finish | // successful finish |
| } catch(const Exception& e) { // global problem | } catch(const Exception& e) { // global problem |
| // don't allocate anything on pool here: | // don't allocate anything on pool here: |
| // possible pool' exception not catch-ed now | // possible pool' exception not catch-ed now |
| // and there could be out-of-memory exception | // and there could be out-of-memory exception |
| const char *body=e.comment(); | const char* body=e.comment(); |
| // log it | // log it |
| SAPI::log(pool, "exception in request exception handler: %s", body); | SAPI::log("exception in request exception handler: %s", body); |
| // | // |
| int content_length=strlen(body); | int content_length=strlen(body); |
| // prepare header | // prepare header |
| SAPI::add_header_attribute(pool, "content-type", "text/plain"); | SAPI::add_header_attribute("content-type", "text/plain"); |
| char content_length_cstr[MAX_NUMBER]; | char content_length_cstr[MAX_NUMBER]; |
| snprintf(content_length_cstr, MAX_NUMBER, "%u", content_length); | snprintf(content_length_cstr, MAX_NUMBER, "%u", content_length); |
| SAPI::add_header_attribute(pool, "content-length", content_length_cstr); | SAPI::add_header_attribute("content-length", content_length_cstr); |
| // send header | // send header |
| SAPI::send_header(pool); | SAPI::send_header(); |
| // send body | // send body |
| if(!r->header_only) | if(!r->header_only) |
| SAPI::send_body(pool, body, content_length); | SAPI::send_body(body, content_length); |
| // unsuccessful finish | // unsuccessful finish |
| } | } |
| Line 331 static int parser_handler(request_rec *r | Line 346 static int parser_handler(request_rec *r |
| return OK; | return OK; |
| } | } |
| #if _MSC_VER | |
| int failed_new(size_t size) { | |
| SAPI::die("out of memory in 'new', failed to allocated %u bytes", size); | |
| return 0; // not reached | |
| } | |
| #endif | |
| #ifdef HAVE_SET_NEW_HANDLER | |
| void failed_new() { | |
| SAPI::die("out of memory in 'new'"); | |
| } | |
| #endif | |
| /*--------------------------------------------------------------------------*/ | /*--------------------------------------------------------------------------*/ |
| /* */ | /* */ |
| /* Now let's declare routines for each of the callback phase in order. */ | /* Now let's declare routines for each of the callback phase in order. */ |
| Line 387 static void setup_module_cells() { | Line 389 static void setup_module_cells() { |
| return; | return; |
| globals_inited=true; | globals_inited=true; |
| #ifdef WIN32 | |
| _set_new_handler(failed_new); | |
| #endif | |
| #ifdef HAVE_SET_NEW_HANDLER | |
| std::set_new_handler(failed_new); | |
| #endif | |
| /* | /* |
| * allocate our module-private pool. | * allocate our module-private pool. |
| */ | */ |
| Line 402 static void setup_module_cells() { | Line 396 static void setup_module_cells() { |
| /// no trying to __try here [yet] | /// no trying to __try here [yet] |
| try { | try { |
| // init socks | // init socks |
| init_socks(pool); | pa_init_socks(); |
| // init global classes | // init global classes |
| init_methoded_array(pool); | init_methoded_array(); |
| // init global variables | // init global variables |
| pa_globals_init(pool); | pa_globals_init(); |
| } catch(const Exception& e) { // global problem | } catch(const Exception& e) { // global problem |
| SAPI::die("setup_module_cells failed: %s", e.comment()); | SAPI::abort("setup_module_cells failed: %s", e.comment()); |
| } | } |
| } | } |
| Line 478 static void *parser_merge_dir_config(poo | Line 472 static void *parser_merge_dir_config(poo |
| Parser_module_config *pconf = (Parser_module_config *) parent_conf; | Parser_module_config *pconf = (Parser_module_config *) parent_conf; |
| Parser_module_config *nconf = (Parser_module_config *) newloc_conf; | Parser_module_config *nconf = (Parser_module_config *) newloc_conf; |
| merged_config->parser_root_config_filespec = ap_pstrdup(p, nconf->parser_root_config_filespec? | merged_config->parser_config_filespec = ap_pstrdup(p, nconf->parser_config_filespec? |
| nconf->parser_root_config_filespec:pconf->parser_root_config_filespec); | nconf->parser_config_filespec:pconf->parser_config_filespec); |
| merged_config->parser_site_config_filespec = ap_pstrdup(p, nconf->parser_site_config_filespec? | |
| nconf->parser_site_config_filespec:pconf->parser_site_config_filespec); | |
| merged_config->parser_status_allowed= | merged_config->parser_status_allowed= |
| pconf->parser_status_allowed || | pconf->parser_status_allowed || |
| nconf->parser_status_allowed; | nconf->parser_status_allowed; |
| Line 540 static void *parser_merge_server_config( | Line 532 static void *parser_merge_server_config( |
| * Our inheritance rules are our own, and part of our module's semantics. | * Our inheritance rules are our own, and part of our module's semantics. |
| * Basically, just note whence we came. | * Basically, just note whence we came. |
| */ | */ |
| merged_config->parser_root_config_filespec = ap_pstrdup(p, s2conf->parser_root_config_filespec? | merged_config->parser_config_filespec = ap_pstrdup(p, s2conf->parser_config_filespec? |
| s2conf->parser_root_config_filespec:s1conf->parser_root_config_filespec); | s2conf->parser_config_filespec:s1conf->parser_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_status_allowed= | merged_config->parser_status_allowed= |
| s1conf->parser_status_allowed || | s1conf->parser_status_allowed || |
| s2conf->parser_status_allowed; | s2conf->parser_status_allowed; |
| Line 623 static int parser_access_checker(request | Line 613 static int parser_access_checker(request |
| static const command_rec parser_cmds[] = | static const command_rec parser_cmds[] = |
| { | { |
| { | { |
| "ParserRootConfig", /* directive name */ | "ParserConfig", /* directive name */ |
| (const char *(*)(void))((void *)cmd_parser_config), // config action routine | (const char* (*)(void))((void *)cmd_parser_config), // config action routine |
| (void*)true, /* argument to include in call */ | (void*)0, /* argument to include in call */ |
| (int)(ACCESS_CONF|RSRC_CONF), /* where available */ | |
| TAKE1, /* arguments */ | |
| "Parser root config filespec (Admin)" // directive description | |
| }, | |
| { | |
| "ParserSiteConfig", /* directive name */ | |
| (const char *(*)(void))((void *)cmd_parser_config), // config action routine | |
| (void*)false, /* argument to include in call */ | |
| (int)(OR_OPTIONS), /* where available */ | (int)(OR_OPTIONS), /* where available */ |
| TAKE1, /* arguments */ | TAKE1, /* arguments */ |
| "Parser site config filespec" // directive description | "Parser config filespec" // directive description |
| }, | }, |
| { | { |
| "ParserStatusAllowed", /* directive name */ | "ParserStatusAllowed", /* directive name */ |
| (const char *(*)(void))((void *)cmd_parser_status_allowed), // config action routine | (const char* (*)(void))((void *)cmd_parser_status_allowed), // config action routine |
| (void*)0, /* argument to include in call */ | (void*)0, /* argument to include in call */ |
| (int)(ACCESS_CONF), /* where available */ | (int)(ACCESS_CONF), /* where available */ |
| NO_ARGS, /* arguments */ | NO_ARGS, /* arguments */ |
| Line 706 module MODULE_VAR_EXPORT parser3_module | Line 688 module MODULE_VAR_EXPORT parser3_module |
| }; | }; |
| #if defined(_MSC_VER) | #if defined(_MSC_VER) |
| # define APACHE_WIN32_SRC "/parser3project/win32apache13/src" | # define APACHE_WIN32_SRC "/parser3project/win32/apache13/src" |
| # ifdef _DEBUG | # ifdef _DEBUG |
| # pragma comment(lib, APACHE_WIN32_SRC "/CoreD/ApacheCore.lib") | # pragma comment(lib, APACHE_WIN32_SRC "/CoreD/ApacheCore.lib") |
| # else | # else |