--- parser3/src/targets/cgi/parser3.C 2004/06/18 09:17:11 1.228 +++ parser3/src/targets/cgi/parser3.C 2007/11/27 09:57:39 1.246 @@ -1,11 +1,11 @@ /** @file Parser: scripting and CGI main. - Copyright(c) 2001-2004 ArtLebedev Group (http://www.artlebedev.com) + Copyright(c) 2001-2005 ArtLebedev Group (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) */ -static const char * const IDENT_PARSER3_C="$Date: 2004/06/18 09:17:11 $"; +static const char * const IDENT_PARSER3_C="$Date: 2007/11/27 09:57:39 $"; #include "pa_config_includes.h" @@ -22,9 +22,15 @@ static const char * const IDENT_PARSER3_ #ifdef WIN32 # include -# include "getopt.h" -#else -# include +#endif + +// defines + +// comment remove me after debugging +//#define PA_DEBUG_CGI_ENTRY_EXIT "c:\\parser\\debug-parser3.log" + +#if _MSC_VER && !defined(_DEBUG) +# define PA_SUPPRESS_SYSTEM_EXCEPTION #endif //#define DEBUG_MAILRECEIVE "mailreceive.eml" @@ -42,6 +48,9 @@ static const char* argv0; static const char* config_filespec_cstr=0; static bool fail_on_config_read_problem=true; +static int args_skip=1; +static char** argv_all = NULL; + static bool cgi; ///< we were started as CGI? static bool mail_received=false; ///< we were started with -m option? [asked to parse incoming message to $mail:received] @@ -65,6 +74,10 @@ static void log(const char* fmt, va_list f=fopen(log_by_env, "at"); opened=f!=0; } +#ifdef PA_DEBUG_CGI_ENTRY_EXIT + f=fopen(PA_DEBUG_CGI_ENTRY_EXIT, "at"); + opened=f!=0; +#endif if(!opened && config_filespec_cstr) { char beside_config_path[MAX_STRING]; @@ -93,23 +106,41 @@ static void log(const char* fmt, va_list time_t t=time(0); if(const char* stamp=ctime(&t)) { // never saw that if(size_t len=strlen(stamp)) // saw once stamp being ="" - fprintf(f, "[%.*s] ", len-1, stamp); + fprintf(f, "[%.*s] [%u] ", len-1, stamp, + (unsigned int)getpid() + ); } // message - char buf[MAX_STRING]; - size_t size=vsnprintf(buf, MAX_STRING, fmt, args); - remove_crlf(buf, buf+size); - + char buf[MAX_LOG_STRING]; + size_t size=vsnprintf(buf, MAX_LOG_STRING, fmt, args); + size=remove_crlf(buf, buf+size); fwrite(buf, size, 1, f); + + if(request_info) + fprintf(f, " [uri=%s, method=%s, cl=%u]", + request_info->uri? request_info->uri: "", + request_info->method? request_info->method: "", + request_info->content_length); + else + fputs(" [no request info]", f); + // newline - fprintf(f, "\n"); + fputs("\n", f); if(opened) fclose(f); else fflush(f); } +#ifdef PA_DEBUG_CGI_ENTRY_EXIT +static void log(const char* fmt, ...) { + va_list args; + va_start(args,fmt); + log(fmt, args); + va_end(args); +} +#endif // appends to parser3.log located beside my binary if openable, to stderr otherwize void SAPI::log(SAPI_Info&, const char* fmt, ...) { @@ -166,14 +197,14 @@ void SAPI::die(const char* fmt, ...) { va_list args; va_start(args, fmt); die_or_abort(fmt, args, false/*write core?*/); - va_end(args); +//unreachable anyway 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); +//unreachable anyway va_end(args); } char* SAPI::get_env(SAPI_Info& , const char* name) { @@ -207,7 +238,7 @@ size_t SAPI::read_post(SAPI_Info& , char } void SAPI::add_header_attribute(SAPI_Info& , const char* dont_store_key, const char* dont_store_value) { - if(cgi) + if( cgi && (!request || !request->console.was_used()) ) printf("%s: %s\n", dont_store_key, dont_store_value); } @@ -221,8 +252,8 @@ void SAPI::send_header(SAPI_Info& ) { } } -void SAPI::send_body(SAPI_Info& , const void *buf, size_t size) { - stdout_write(buf, size); +size_t SAPI::send_body(SAPI_Info& , const void *buf, size_t size) { + return stdout_write(buf, size); } // @@ -266,8 +297,15 @@ static void SIGUSR1_handler(int /*sig*/) #endif #ifdef SIGPIPE +#define SIGPIPE_NAME "SIGPIPE" +static const String sigpipe_name(SIGPIPE_NAME); static void SIGPIPE_handler(int /*sig*/){ - log_signal("SIGPIPE"); + Value* sigpipe=0; + if(request) + sigpipe=request->main_class.get_element(sigpipe_name, request->main_class, false); + if(sigpipe && sigpipe->as_bool()) + log_signal(SIGPIPE_NAME); + execution_canceled=true; if(request) request->set_interrupted(true); @@ -282,9 +320,9 @@ const char* maybe_reconstruct_IIS_status // and can consider that as an indication that this is IIS way to report errors if(original - && isdigit(original[0]) - && isdigit(original[1]) - && isdigit(original[2]) + && isdigit((unsigned char)original[0]) + && isdigit((unsigned char)original[1]) + && isdigit((unsigned char)original[2]) && original[3]==';') { size_t original_len=strlen(original); @@ -326,15 +364,20 @@ main workhorse wich is tested but seems slow. */ static void real_parser_handler(const char* filespec_to_process, - const char* request_method, bool header_only) { + const char* request_method, bool header_only) +{ // init socks pa_socks_init(); - + // init global variables pa_globals_init(); if(!filespec_to_process || !*filespec_to_process) - SAPI::die("Parser/%s", PARSER_VERSION); + SAPI::die("Parser/%s" +#ifdef PA_DEBUG_CGI_ENTRY_EXIT + " with entry/exit tracing" +#endif + , PARSER_VERSION); // Request info Request_info request_info; memset(&request_info, 0, sizeof(request_info)); @@ -348,7 +391,7 @@ static void real_parser_handler(const ch memcpy(document_root_buf, filespec_to_process, len); document_root_buf[len]=0; request_info.document_root=document_root_buf; } else - throw Exception("parser.runtime", + throw Exception(PARSER_RUNTIME, 0, "CGI: no PATH_INFO defined(in reinventing DOCUMENT_ROOT)"); } else { @@ -432,11 +475,25 @@ static void real_parser_handler(const ch request_info.cookie=getenv("HTTP_COOKIE"); request_info.mail_received=mail_received; + request_info.argv=argv_all; + request_info.args_skip=args_skip; + // get request_info ptr for signal handlers ::request_info=&request_info; if(execution_canceled) SAPI::die("Execution canceled"); +#ifdef PA_DEBUG_CGI_ENTRY_EXIT + log("request_info: method=%s, uri=%s, q=%s, dr=%s, pt=%s, cookies=%s, cl=%u", + request_info.method, + request_info.uri, + request_info.query_string, + request_info.document_root, + request_info.path_translated, + request_info.cookie, + request_info.content_length); +#endif + // prepare to process request Request request(SAPI_info, request_info, cgi ? String::Language(String::L_HTML|String::L_OPTIMIZE_BIT) : String::L_AS_IS, @@ -478,7 +535,7 @@ static void real_parser_handler(const ch // no request [prevent signal handlers from accessing invalid memory] ::request=0; - + // finalize global variables pa_globals_done(); @@ -486,71 +543,62 @@ static void real_parser_handler(const ch pa_socks_done(); } -#if _MSC_VER && !defined(_DEBUG) -# define PA_USE___TRY -struct Parser_executed { - bool with_system_exception; - LPEXCEPTION_POINTERS system_exception; -}; -#endif - -static -#ifdef PA_USE___TRY -Parser_executed -#else -void -#endif -call_real_parser_handler__do_SEH_return_it( - const char* filespec_to_process, - const char* request_method, bool header_only) { -#ifdef PA_USE___TRY - Parser_executed result={false}; - __try { -#endif +#ifdef PA_SUPPRESS_SYSTEM_EXCEPTION +static const Exception +call_real_parser_handler__do_PEH_return_it( + const char* filespec_to_process, + const char* request_method, bool header_only) +{ + try { real_parser_handler( filespec_to_process, request_method, header_only); - -#ifdef PA_USE___TRY - } __except ( - (result.system_exception=GetExceptionInformation()), - EXCEPTION_EXECUTE_HANDLER) { - result.with_system_exception=true; + } catch(const Exception& e) { + return e; } - return result; -#endif + + return Exception(); } +static void call_real_parser_handler__supress_system_exception( + const char* filespec_to_process, + const char* request_method, bool header_only) +{ + Exception parser_exception; + LPEXCEPTION_POINTERS system_exception=0; -static void call_real_parser_handler__do_SEH( - const char* filespec_to_process, - const char* request_method, bool header_only) { -#ifdef PA_USE___TRY - Parser_executed executed= -#endif - call_real_parser_handler__do_SEH_return_it(filespec_to_process, + __try { + parser_exception=call_real_parser_handler__do_PEH_return_it( + filespec_to_process, request_method, header_only); + } __except ( + (system_exception=GetExceptionInformation()), + EXCEPTION_EXECUTE_HANDLER) + { -#ifdef PA_USE___TRY - if(executed.with_system_exception) - if(executed.system_exception) - if(_EXCEPTION_RECORD *er=executed.system_exception->ExceptionRecord) - throw Exception(0, + if(system_exception) + if(_EXCEPTION_RECORD *er=system_exception->ExceptionRecord) + throw Exception("system", 0, - "Exception 0x%08X at 0x%08X", er->ExceptionCode, er->ExceptionAddress); + "0x%08X at 0x%08X", er->ExceptionCode, er->ExceptionAddress); else - throw Exception(0, + throw Exception("system", 0, - "Exception "); + ""); else - throw Exception(0, + throw Exception("system", 0, - "Exception "); -#endif + ""); + } + + if(parser_exception) + throw Exception(parser_exception); } +#endif static void usage(const char* program) { printf( - "Parser/%s Copyright(c) 2001-2004 ArtLebedev Group (http://www.artlebedev.com)\n" + "Parser/%s\n" + "Copyright(c) 2001-2007 ArtLebedev Group (http://www.artlebedev.com)\n" "Author: Alexandr Petrosian (http://paf.design.ru)\n" "\n" "Usage: %s [options] file\n" @@ -565,7 +613,10 @@ static void usage(const char* program) { exit(EINVAL); } -int main(int argc, char *argv[]) { +int main(size_t argc, char *argv[]) { +#ifdef PA_DEBUG_CGI_ENTRY_EXIT + log("main: entry"); +#endif //_asm int 3; GC_java_finalization=0; @@ -606,6 +657,7 @@ int main(int argc, char *argv[]) { #ifdef _DEBUG //_crtBreakAlloc=46; #endif + argv_all=argv; argv0=argv[0]; umask(2); @@ -623,38 +675,44 @@ int main(int argc, char *argv[]) { if(raw_filespec_to_process && !*raw_filespec_to_process) raw_filespec_to_process=0; } else { - optind = 1; - opterr = 0; - int c; - while((c = getopt(argc, argv, "hf:" -#ifdef WITH_MAILRECEIVE - "m" -#endif - )) > 0) { - switch (c) { - case 'h': - usage(argv[0]); - break; - case 'f': - config_filespec_cstr=optarg; + size_t optind=1; + while(optind < argc){ + char *carg = argv[optind]; + if(carg[0] != '-') break; + + for(size_t k = 1; k < strlen(carg); k++){ + char c = carg[k]; + switch (c) { + case 'h': + usage(argv[0]); + break; + case 'f': + if(optind < argc - 1){ + optind++; + config_filespec_cstr=argv[optind]; + } + break; #ifdef WITH_MAILRECEIVE - case 'm': - mail_received=true; - break; -#endif - default: - fprintf(stderr, "%s: invalid option '%c'\n", argv[0], optopt); - usage(argv[0]); - break; + case 'm': + mail_received=true; + break; +#endif + default: + fprintf(stderr, "%s: invalid option '%c'\n", argv[0], c); + usage(argv[0]); + break; + } } + optind++; } - if (optind != argc - 1) { + + if (optind > argc - 1) { fprintf(stderr, "%s: file not specified\n", argv[0]); usage(argv[0]); } - - raw_filespec_to_process=argv[optind++]; + raw_filespec_to_process=argv[optind]; + args_skip=optind; } #ifdef WIN32 @@ -685,17 +743,20 @@ int main(int argc, char *argv[]) { bool header_only=request_method && strcasecmp(request_method, "HEAD")==0; try { // global try - call_real_parser_handler__do_SEH( +#ifdef PA_SUPPRESS_SYSTEM_EXCEPTION + call_real_parser_handler__supress_system_exception( +#else + real_parser_handler( +#endif filespec_to_process, request_method, header_only); } 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(); char buf[MAX_STRING]; - snprintf(buf, MAX_STRING, "exception in request exception handler: %s", - body); + snprintf(buf, MAX_STRING, "Unhandled exception %s", + e.comment()); // log it SAPI::log(SAPI_info, "%s", buf); @@ -718,5 +779,8 @@ int main(int argc, char *argv[]) { // unsuccessful finish } +#ifdef PA_DEBUG_CGI_ENTRY_EXIT + log("main: successful return"); +#endif return 0; }