Annotation of parser3/src/targets/apache/mod_parser3_core.C, revision 1.1
1.1 ! moko 1: /** @file
! 2: Parser: apache 1.3 module, part, compiled by parser3project.
! 3:
! 4: Copyright (c) 2001-2005 ArtLebedev Group (http://www.artlebedev.com)
! 5: Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
! 6: */
! 7:
! 8: static const char * const IDENT_MOD_PARSER3_MAIN_C="$Date: 2009-10-06 11:40:23 $";
! 9:
! 10: #include "pa_config_includes.h"
! 11:
! 12: #include "pa_globals.h"
! 13:
! 14: #include "pa_httpd.h"
! 15:
! 16: #include "pa_common.h"
! 17: #include "pa_sapi.h"
! 18: #include "classes.h"
! 19: #include "pa_request.h"
! 20: #include "pa_version.h"
! 21: #include "pa_socks.h"
! 22:
! 23: #if _MSC_VER && !defined(_DEBUG)
! 24: # include <windows.h>
! 25: # define PA_SUPPRESS_SYSTEM_EXCEPTION
! 26: #endif
! 27:
! 28: // generals
! 29:
! 30: const char* pa_version() {
! 31: return "Parser/"PARSER_VERSION;
! 32: }
! 33:
! 34: void pa_setup_module_cells() {
! 35: static bool globals_inited=false;
! 36: if(globals_inited)
! 37: return;
! 38: globals_inited=true;
! 39:
! 40: /// no trying to __try here [yet]
! 41: try {
! 42: // init socks
! 43: pa_socks_init();
! 44:
! 45: // init global variables
! 46: pa_globals_init();
! 47: } catch(const Exception& e) { // global problem
! 48: SAPI::abort("setup_module_cells failed: %s", e.comment());
! 49: }
! 50: }
! 51:
! 52: void pa_destroy_module_cells() {
! 53: pa_globals_done();
! 54:
! 55: pa_socks_done();
! 56: }
! 57:
! 58:
! 59: //@{
! 60: /// SAPI func decl
! 61:
! 62: class SAPI_Info {
! 63: public:
! 64: pa_request_rec* r;
! 65: };
! 66:
! 67: void SAPI::log(SAPI_Info& SAPI_info, const char* fmt, ...) {
! 68: va_list args;
! 69: va_start(args,fmt);
! 70: char buf[MAX_LOG_STRING];
! 71: size_t size=vsnprintf(buf, MAX_LOG_STRING, fmt, args);
! 72: size=remove_crlf(buf, buf+size);
! 73: pa_ap_log_rerror(0, 0, PA_APLOG_ERR | PA_APLOG_NOERRNO, SAPI_info.r, "%s", buf);
! 74: va_end(args);
! 75: }
! 76:
! 77: static void die_or_abort(const char* fmt, va_list args, bool write_core) {
! 78: char buf[MAX_LOG_STRING];
! 79: size_t size=vsnprintf(buf, MAX_LOG_STRING, fmt, args);
! 80: size=remove_crlf(buf, buf+size);
! 81: pa_ap_log_error(PA_APLOG_MARK, PA_APLOG_EMERG, 0, "%s", buf);
! 82:
! 83: // exit & try to produce core dump
! 84: if(write_core)
! 85: abort();
! 86: else
! 87: exit(1);
! 88: }
! 89:
! 90: void SAPI::die(const char* fmt, ...) {
! 91: va_list args;
! 92: va_start(args, fmt);
! 93: die_or_abort(fmt, args, false/*write core?*/);
! 94: va_end(args);
! 95: }
! 96:
! 97: void SAPI::abort(const char* fmt, ...) {
! 98: va_list args;
! 99: va_start(args, fmt);
! 100: die_or_abort(fmt, args, true/*write core?*/);
! 101: va_end(args);
! 102: }
! 103:
! 104: char* SAPI::get_env(SAPI_Info& SAPI_info, const char* name) {
! 105: const char* dont_return_me=pa_ap_table_get(SAPI_info.r->subprocess_env, name);
! 106: return dont_return_me?pa_strdup(dont_return_me):0;
! 107: }
! 108:
! 109: #ifndef DOXYGEN
! 110: struct SAPI_environment_append_info {
! 111: const char** cur;
! 112: };
! 113: #endif
! 114: static const char* mk_env_pair(const char* key, const char* value) {
! 115: char *result=new(PointerFreeGC) char[strlen(key)+1/*=*/+strlen(value)+1/*0*/];
! 116: strcpy(result, key); strcat(result, "="); strcat(result, value);
! 117: return result;
! 118: }
! 119: static int SAPI_environment_append(void *d, const char* k, const char* val) {
! 120: if( k && val ) {
! 121: SAPI_environment_append_info& info=
! 122: *static_cast<SAPI_environment_append_info *>(d);
! 123: *info.cur++=mk_env_pair(k, val);
! 124: }
! 125: return 1/*true*/;
! 126: }
! 127: const char* const* SAPI::environment(SAPI_Info& SAPI_info) {
! 128: const pa_table *t=SAPI_info.r->subprocess_env;
! 129: const char** result=new(UseGC) const char*[pa_ap_table_size(t)+1/*0*/];
! 130: SAPI_environment_append_info info={result};
! 131: pa_ap_table_do(SAPI_environment_append, &info, t, 0); *info.cur=0; // mark EOE
! 132: return result;
! 133: }
! 134:
! 135: size_t SAPI::read_post(SAPI_Info& SAPI_info, char *buf, size_t max_bytes) {
! 136: /* pa_ap_log_error(PA_APLOG_MARK, PA_APLOG_DEBUG, SAPI_info.r->server,
! 137: "mod_parser3: SAPI::read_post(max=%u)", max_bytes);
! 138: */
! 139: int retval;
! 140: if((retval = pa_ap_setup_client_block(SAPI_info.r, PA_REQUEST_CHUNKED_ERROR)))
! 141: return 0;
! 142: if(!pa_ap_should_client_block(SAPI_info.r))
! 143: return 0;
! 144:
! 145: uint total_read_bytes=0;
! 146: void (*handler)(int)=pa_signal(PA_SIGPIPE, PA_SIG_IGN);
! 147: while (total_read_bytes<max_bytes) {
! 148: pa_ap_hard_timeout("Read POST information", SAPI_info.r); /* start timeout timer */
! 149: uint read_bytes=
! 150: pa_ap_get_client_block(SAPI_info.r, buf+total_read_bytes, max_bytes-total_read_bytes);
! 151: pa_ap_reset_timeout(SAPI_info.r);
! 152: if (read_bytes<=0)
! 153: break;
! 154: total_read_bytes+=read_bytes;
! 155: }
! 156: pa_signal(PA_SIGPIPE, handler);
! 157: return total_read_bytes;
! 158: }
! 159:
! 160: /// @test location provide with protocol. think about internal redirects
! 161: void SAPI::add_header_attribute(SAPI_Info& SAPI_info,
! 162: const char* dont_store_key, const char* dont_store_value) {
! 163: if(strcasecmp(dont_store_key, "location")==0)
! 164: *SAPI_info.r->status=302;
! 165:
! 166: if(strcasecmp(dont_store_key, HTTP_CONTENT_TYPE)==0) {
! 167: /* r->content_type, *not* r->headers_out("Content-type"). If you don't
! 168: * set it, it will be filled in with the server's default type (typically
! 169: * "text/plain"). You *must* also ensure that r->content_type is lower
! 170: * case.
! 171: */
! 172: *SAPI_info.r->content_type = pa_ap_pstrdup(SAPI_info.r->pool, dont_store_value);
! 173: } else if(strcasecmp(dont_store_key, HTTP_STATUS)==0)
! 174: *SAPI_info.r->status=atoi(dont_store_value);
! 175: else
! 176: pa_ap_table_addn(SAPI_info.r->headers_out,
! 177: pa_ap_pstrdup(SAPI_info.r->pool, capitalize(dont_store_key)),
! 178: pa_ap_pstrdup(SAPI_info.r->pool, dont_store_value));
! 179: }
! 180:
! 181: void SAPI::send_header(SAPI_Info& SAPI_info) {
! 182: pa_ap_hard_timeout("Send header", SAPI_info.r);
! 183: pa_ap_send_http_header(SAPI_info.r);
! 184: pa_ap_kill_timeout(SAPI_info.r);
! 185: }
! 186:
! 187: size_t SAPI::send_body(SAPI_Info& SAPI_info, const void *buf, size_t size) {
! 188: pa_ap_hard_timeout("Send body", SAPI_info.r);
! 189: size = (size_t)pa_ap_rwrite(buf, size, SAPI_info.r);
! 190: pa_ap_kill_timeout(SAPI_info.r);
! 191: return size;
! 192: }
! 193:
! 194: //@}
! 195:
! 196: #if !defined(PA_DEBUG_DISABLE_GC) && !defined(WIN32)
! 197: extern long GC_large_alloc_warn_suppressed;
! 198: #endif
! 199:
! 200: /**
! 201: main workhorse
! 202:
! 203: @todo intelligent cache-control
! 204: */
! 205: static void real_parser_handler(SAPI_Info& SAPI_info, Parser_module_config *dcfg) {
! 206: // collect garbage from prev request
! 207: #if !defined(PA_DEBUG_DISABLE_GC) && !defined(WIN32)
! 208: {
! 209: int saved=GC_dont_gc;
! 210: GC_dont_gc=0;
! 211: GC_gcollect();
! 212: GC_dont_gc=saved;
! 213: GC_large_alloc_warn_suppressed=0;
! 214: }
! 215: #endif
! 216:
! 217: // populate env
! 218: pa_ap_add_common_vars(SAPI_info.r);
! 219: pa_ap_add_cgi_vars(SAPI_info.r);
! 220:
! 221: // Request info
! 222: Request_info request_info; memset(&request_info, 0, sizeof(request_info));
! 223:
! 224: request_info.document_root=SAPI::get_env(SAPI_info, "DOCUMENT_ROOT");
! 225: request_info.path_translated=SAPI_info.r->filename;
! 226: request_info.method=SAPI_info.r->method;
! 227: request_info.query_string=SAPI_info.r->args;
! 228: request_info.uri=SAPI::get_env(SAPI_info, "REQUEST_URI");
! 229: request_info.content_type=SAPI::get_env(SAPI_info, "CONTENT_TYPE");
! 230: const char* content_length=SAPI::get_env(SAPI_info, "CONTENT_LENGTH");
! 231: request_info.content_length=content_length?atoi(content_length):0;
! 232: request_info.cookie=SAPI::get_env(SAPI_info, "HTTP_COOKIE");
! 233: request_info.mail_received=false;
! 234:
! 235: //_asm int 3;
! 236: // prepare to process request
! 237: Request request(
! 238: SAPI_info,
! 239: request_info,
! 240: String::Language(String::L_HTML|String::L_OPTIMIZE_BIT),
! 241: dcfg->parser_status_allowed?true:false
! 242: );
! 243:
! 244: // process the request
! 245: request.core(
! 246: dcfg->parser_config_filespec, true, // /path/to/config
! 247: SAPI_info.r->header_only!=0);
! 248: }
! 249:
! 250: #ifdef PA_SUPPRESS_SYSTEM_EXCEPTION
! 251: static const Exception
! 252: call_real_parser_handler__do_PEH_return_it(
! 253: SAPI_Info& SAPI_info, Parser_module_config *dcfg)
! 254: {
! 255: try {
! 256: real_parser_handler(SAPI_info, dcfg);
! 257: } catch(const Exception& e) {
! 258: return e;
! 259: }
! 260:
! 261: return Exception();
! 262: }
! 263: static void call_real_parser_handler__supress_system_exception(
! 264: SAPI_Info& SAPI_info, Parser_module_config *dcfg)
! 265: {
! 266: Exception parser_exception;
! 267: LPEXCEPTION_POINTERS system_exception=0;
! 268:
! 269: __try {
! 270: parser_exception=call_real_parser_handler__do_PEH_return_it(
! 271: SAPI_info, dcfg);
! 272: } __except (
! 273: (system_exception=GetExceptionInformation()),
! 274: EXCEPTION_EXECUTE_HANDLER)
! 275: {
! 276:
! 277: if(system_exception)
! 278: if(_EXCEPTION_RECORD *er=system_exception->ExceptionRecord)
! 279: throw Exception("system",
! 280: 0,
! 281: "0x%08X at 0x%08X", er->ExceptionCode, er->ExceptionAddress);
! 282: else
! 283: throw Exception("system",
! 284: 0,
! 285: "<no exception record>");
! 286: else
! 287: throw Exception("system",
! 288: 0,
! 289: "<no exception information>");
! 290: }
! 291:
! 292: if(parser_exception)
! 293: throw Exception(parser_exception);
! 294: }
! 295: #endif
! 296:
! 297: /// @test r->finfo.st_mode check seems to work only on win32
! 298: int pa_parser_handler(pa_request_rec *r, Parser_module_config *dcfg) {
! 299: //_asm int 3;
! 300:
! 301: // SAPI info
! 302: SAPI_Info SAPI_info; SAPI_info.r=r;
! 303:
! 304: //_asm int 3;
! 305: if(r->finfo->st_mode == 0)
! 306: return PA_HTTP_NOT_FOUND;
! 307:
! 308: /* A flag which modules can set, to indicate that the data being
! 309: * returned is volatile, and clients should be told not to cache it.
! 310: */
! 311: // r->no_cache=1;
! 312:
! 313: try { // global try
! 314: #ifdef PA_SUPPRESS_SYSTEM_EXCEPTION
! 315: call_real_parser_handler__supress_system_exception(
! 316: #else
! 317: real_parser_handler(
! 318: #endif
! 319: SAPI_info, dcfg);
! 320:
! 321: // successful finish
! 322: } catch(const Exception& e) { // global problem
! 323: // don't allocate anything on pool here:
! 324: // possible pool' exception not catch-ed now
! 325: // and there could be out-of-memory exception
! 326: char buf[MAX_STRING];
! 327: snprintf(buf, MAX_STRING, "Unhandled exception %s",
! 328: e.comment());
! 329: // log it
! 330: SAPI::log(SAPI_info, "%s", buf);
! 331:
! 332: //
! 333: int content_length=strlen(buf);
! 334:
! 335: // prepare header
! 336: // capitalized headers are used for preventing malloc during capitalization
! 337: SAPI::add_header_attribute(SAPI_info, HTTP_CONTENT_TYPE_CAPITALIZED, "text/plain");
! 338: // don't use 'format' function because it calls malloc
! 339: char content_length_cstr[MAX_NUMBER];
! 340: snprintf(content_length_cstr, MAX_NUMBER, "%u", content_length);
! 341: SAPI::add_header_attribute(SAPI_info, HTTP_CONTENT_LENGTH_CAPITALIZED, content_length_cstr);
! 342:
! 343: // send header
! 344: SAPI::send_header(SAPI_info);
! 345:
! 346: // send body
! 347: if(!r->header_only)
! 348: SAPI::send_body(SAPI_info, buf, content_length);
! 349:
! 350: // unsuccessful finish
! 351: }
! 352:
! 353: /*
! 354: * We did what we wanted to do, so tell the rest of the server we
! 355: * succeeded.
! 356: */
! 357: return PA_OK;
! 358: }
E-mail: