|
|
| version 1.243, 2007/08/17 08:16:11 | version 1.260, 2012/03/16 09:24:16 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: scripting and CGI main. | Parser: scripting and CGI main. |
| Copyright(c) 2001-2005 ArtLebedev Group (http://www.artlebedev.com) | Copyright (c) 2001-2012 Art. Lebedev Studio (http://www.artlebedev.com) |
| Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) | Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) |
| */ | */ |
| static const char * const IDENT_PARSER3_C="$Date$"; | volatile const char * IDENT_PARSER3_C="$Id$"; |
| #include "pa_config_includes.h" | #include "pa_config_includes.h" |
| Line 22 static const char * const IDENT_PARSER3_ | Line 22 static const char * const IDENT_PARSER3_ |
| #ifdef WIN32 | #ifdef WIN32 |
| # include <windows.h> | # include <windows.h> |
| # include "getopt.h" | |
| #else | |
| # include <getopt.h> | |
| #endif | #endif |
| // defines | // defines |
| Line 51 static const char* argv0; | Line 48 static const char* argv0; |
| static const char* config_filespec_cstr=0; | static const char* config_filespec_cstr=0; |
| static bool fail_on_config_read_problem=true; | 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 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] | static bool mail_received=false; ///< we were started with -m option? [asked to parse incoming message to $mail:received] |
| Line 112 static void log(const char* fmt, va_list | Line 112 static void log(const char* fmt, va_list |
| } | } |
| // message | // message |
| char buf[MAX_STRING]; | char buf[MAX_LOG_STRING]; |
| size_t size=vsnprintf(buf, MAX_STRING, fmt, args); | size_t size=vsnprintf(buf, MAX_LOG_STRING, fmt, args); |
| remove_crlf(buf, buf+size); | size=remove_crlf(buf, buf+size); |
| fwrite(buf, size, 1, f); | fwrite(buf, size, 1, f); |
| if(request_info) | if(request_info) |
| Line 151 void SAPI::log(SAPI_Info&, const char* f | Line 151 void SAPI::log(SAPI_Info&, const char* f |
| } | } |
| static void die_or_abort(const char* fmt, va_list args, bool write_core) { | static void die_or_abort(const char* fmt, va_list args, bool write_core) { |
| // log | |
| // logging is more important than user | |
| // she can cancel download, we'd get SIGPIPE, | |
| // nothing would be logged then | |
| ::log(fmt, args); | |
| // inform user | // inform user |
| char body[MAX_STRING]; | char body[MAX_STRING]; |
| Line 165 static void die_or_abort(const char* fmt | Line 158 static void die_or_abort(const char* fmt |
| // prepare header | // prepare header |
| // let's be honest, that's bad we couldn't produce valid output | // let's be honest, that's bad we couldn't produce valid output |
| SAPI::add_header_attribute(SAPI_info, "status", "500"); | // capitalized headers passed for preventing malloc during capitalization |
| SAPI::add_header_attribute(SAPI_info, "content-type", "text/plain"); | SAPI::add_header_attribute(SAPI_info, HTTP_STATUS_CAPITALIZED, "500"); |
| SAPI::add_header_attribute(SAPI_info, HTTP_CONTENT_TYPE_CAPITALIZED, "text/plain"); | |
| // don't use 'format' function because it calls malloc | |
| char content_length_cstr[MAX_NUMBER]; | char content_length_cstr[MAX_NUMBER]; |
| snprintf(content_length_cstr, sizeof(content_length_cstr), "%u", content_length); | snprintf(content_length_cstr, sizeof(content_length_cstr), "%u", content_length); |
| SAPI::add_header_attribute(SAPI_info, "content-length", content_length_cstr); | SAPI::add_header_attribute(SAPI_info, HTTP_CONTENT_LENGTH_CAPITALIZED, content_length_cstr); |
| // send header | // send header |
| SAPI::send_header(SAPI_info); | SAPI::send_header(SAPI_info); |
| Line 194 static void die_or_abort(const char* fmt | Line 189 static void die_or_abort(const char* fmt |
| } | } |
| void SAPI::die(const char* fmt, ...) { | void SAPI::die(const char* fmt, ...) { |
| va_list args; | va_list args; |
| // logging first, can't log inside die_or_abort due to vsnprintf (bug #106) | |
| va_start(args,fmt); | |
| ::log(fmt, args); | |
| va_end(args); | |
| va_start(args, fmt); | va_start(args, fmt); |
| die_or_abort(fmt, args, false/*write core?*/); | die_or_abort(fmt, args, false /*write core?*/); |
| //unreachable anyway va_end(args); | // va_end(args); |
| } | } |
| void SAPI::abort(const char* fmt, ...) { | void SAPI::abort(const char* fmt, ...) { |
| va_list args; | va_list args; |
| // logging first, can't log inside die_or_abort due to vsnprintf (bug #106) | |
| va_start(args,fmt); | |
| ::log(fmt, args); | |
| va_end(args); | |
| va_start(args, fmt); | va_start(args, fmt); |
| die_or_abort(fmt, args, true/*write core?*/); | die_or_abort(fmt, args, true /*write core?*/); |
| //unreachable anyway va_end(args); | // va_end(args); |
| } | } |
| char* SAPI::get_env(SAPI_Info& , const char* name) { | char* SAPI::get_env(SAPI_Info& , const char* name) { |
| Line 239 size_t SAPI::read_post(SAPI_Info& , char | Line 246 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) { | void SAPI::add_header_attribute(SAPI_Info& , const char* dont_store_key, const char* dont_store_value) { |
| if( cgi && (!request || !request->console.was_used()) ) | if( cgi && (!request || !request->console.was_used()) ) |
| printf("%s: %s\n", dont_store_key, dont_store_value); | printf("%s: %s\n", capitalize(dont_store_key), dont_store_value); |
| } | } |
| /// @todo intelligent cache-control | /// @todo intelligent cache-control |
| Line 302 static const String sigpipe_name(SIGPIPE | Line 309 static const String sigpipe_name(SIGPIPE |
| static void SIGPIPE_handler(int /*sig*/){ | static void SIGPIPE_handler(int /*sig*/){ |
| Value* sigpipe=0; | Value* sigpipe=0; |
| if(request) | if(request) |
| sigpipe=request->main_class.get_element(sigpipe_name, request->main_class, false); | sigpipe=request->main_class.get_element(sigpipe_name); |
| if(sigpipe && sigpipe->as_bool()) | if(sigpipe && sigpipe->as_bool()) |
| log_signal("SIGPIPE"); | log_signal(SIGPIPE_NAME); |
| execution_canceled=true; | execution_canceled=true; |
| if(request) | if(request) |
| Line 355 const char* maybe_reconstruct_IIS_status | Line 362 const char* maybe_reconstruct_IIS_status |
| } | } |
| #endif | #endif |
| class RequestController { | |
| public: | |
| RequestController(Request* r){ | |
| ::request=r; | |
| } | |
| ~RequestController(){ | |
| ::request=0; | |
| } | |
| }; | |
| /** | /** |
| main workhorse | main workhorse |
| Line 475 static void real_parser_handler(const ch | Line 494 static void real_parser_handler(const ch |
| request_info.cookie=getenv("HTTP_COOKIE"); | request_info.cookie=getenv("HTTP_COOKIE"); |
| request_info.mail_received=mail_received; | request_info.mail_received=mail_received; |
| request_info.argv=argv_all; | |
| request_info.args_skip=args_skip; | |
| // get request_info ptr for signal handlers | // get request_info ptr for signal handlers |
| ::request_info=&request_info; | ::request_info=&request_info; |
| if(execution_canceled) | if(execution_canceled) |
| Line 493 static void real_parser_handler(const ch | Line 515 static void real_parser_handler(const ch |
| // prepare to process request | // prepare to process request |
| Request request(SAPI_info, request_info, | Request request(SAPI_info, request_info, |
| cgi ? String::Language(String::L_HTML|String::L_OPTIMIZE_BIT) : String::L_AS_IS, | cgi ? String::Language(String::L_HTML|String::L_OPTIMIZE_BIT) : String::L_AS_IS); |
| true /* status_allowed */); | |
| // get request ptr for signal handlers | { |
| ::request=&request; | // get ::request ptr for signal handlers |
| RequestController rc(&request); | |
| char config_filespec_buf[MAX_STRING]; | char config_filespec_buf[MAX_STRING]; |
| if(!config_filespec_cstr) { | if(!config_filespec_cstr) { |
| const char* config_by_env=getenv(PARSER_CONFIG_ENV_NAME); | const char* config_by_env=getenv(PARSER_CONFIG_ENV_NAME); |
| if(!config_by_env) | if(!config_by_env) |
| config_by_env=getenv(REDIRECT_PREFIX PARSER_CONFIG_ENV_NAME); | config_by_env=getenv(REDIRECT_PREFIX PARSER_CONFIG_ENV_NAME); |
| if(config_by_env) | if(config_by_env) |
| config_filespec_cstr=config_by_env; | config_filespec_cstr=config_by_env; |
| else { | else { |
| // beside by binary | // beside by binary |
| char beside_binary_path[MAX_STRING]; | char beside_binary_path[MAX_STRING]; |
| strncpy(beside_binary_path, argv0, MAX_STRING-1); beside_binary_path[MAX_STRING-1]=0; // filespec of my binary | strncpy(beside_binary_path, argv0, MAX_STRING-1); beside_binary_path[MAX_STRING-1]=0; // filespec of my binary |
| if(!( | if(!( |
| rsplit(beside_binary_path, '/') || | rsplit(beside_binary_path, '/') || |
| rsplit(beside_binary_path, '\\'))) { // strip filename | rsplit(beside_binary_path, '\\'))) { // strip filename |
| // no path, just filename | // no path, just filename |
| // @todo full path, not ./! | // @todo full path, not ./! |
| beside_binary_path[0]='.'; beside_binary_path[1]=0; | beside_binary_path[0]='.'; beside_binary_path[1]=0; |
| } | |
| snprintf(config_filespec_buf, MAX_STRING, | |
| "%s/%s", | |
| beside_binary_path, AUTO_FILE_NAME); | |
| config_filespec_cstr=config_filespec_buf; | |
| fail_on_config_read_problem=entry_exists(config_filespec_cstr); | |
| } | } |
| snprintf(config_filespec_buf, MAX_STRING, | |
| "%s/%s", | |
| beside_binary_path, AUTO_FILE_NAME); | |
| config_filespec_cstr=config_filespec_buf; | |
| fail_on_config_read_problem=entry_exists(config_filespec_cstr); | |
| } | } |
| } | |
| // process the request | |
| // process the request | request.core( |
| request.core( | config_filespec_cstr, fail_on_config_read_problem, |
| config_filespec_cstr, fail_on_config_read_problem, | header_only); |
| header_only); | |
| // no request [prevent signal handlers from accessing invalid memory] | // ::request cleared in RequestController desctructor to prevent signal handlers from accessing invalid memory |
| ::request=0; | } |
| // finalize global variables | // finalize global variables |
| pa_globals_done(); | pa_globals_done(); |
| Line 595 static void call_real_parser_handler__su | Line 617 static void call_real_parser_handler__su |
| static void usage(const char* program) { | static void usage(const char* program) { |
| printf( | printf( |
| "Parser/%s\n" | "Parser/%s\n" |
| "Copyright(c) 2001-2007 ArtLebedev Group (http://www.artlebedev.com)\n" | "Copyright (c) 2001-2012 Art. Lebedev Studio (http://www.artlebedev.com)\n" |
| "Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)\n" | "Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)\n" |
| "\n" | "\n" |
| "Usage: %s [options] file\n" | "Usage: %s [options] file\n" |
| Line 654 int main(int argc, char *argv[]) { | Line 676 int main(int argc, char *argv[]) { |
| #ifdef _DEBUG | #ifdef _DEBUG |
| //_crtBreakAlloc=46; | //_crtBreakAlloc=46; |
| #endif | #endif |
| argv_all=argv; | |
| argv0=argv[0]; | argv0=argv[0]; |
| umask(2); | umask(2); |
| // were we started as CGI? | // were we started as CGI? |
| cgi= | cgi= |
| getenv("SERVER_SOFTWARE") || | ( |
| getenv("SERVER_NAME") || | getenv("SERVER_SOFTWARE") || |
| getenv("GATEWAY_INTERFACE") || | getenv("SERVER_NAME") || |
| getenv("REQUEST_METHOD"); | getenv("GATEWAY_INTERFACE") || |
| getenv("REQUEST_METHOD") | |
| ) | |
| && !getenv("PARSER_VERSION"); | |
| char *raw_filespec_to_process; | char *raw_filespec_to_process; |
| if(cgi) { | if(cgi) { |
| Line 671 int main(int argc, char *argv[]) { | Line 697 int main(int argc, char *argv[]) { |
| if(raw_filespec_to_process && !*raw_filespec_to_process) | if(raw_filespec_to_process && !*raw_filespec_to_process) |
| raw_filespec_to_process=0; | raw_filespec_to_process=0; |
| } else { | } else { |
| optind = 1; | int optind=1; |
| opterr = 0; | while(optind < argc){ |
| int c; | char *carg = argv[optind]; |
| while((c = getopt(argc, argv, "hf:" | if(carg[0] != '-') |
| #ifdef WITH_MAILRECEIVE | |
| "m" | |
| #endif | |
| )) > 0) { | |
| switch (c) { | |
| case 'h': | |
| usage(argv[0]); | |
| break; | |
| case 'f': | |
| config_filespec_cstr=optarg; | |
| break; | 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 | #ifdef WITH_MAILRECEIVE |
| case 'm': | case 'm': |
| mail_received=true; | mail_received=true; |
| break; | break; |
| #endif | #endif |
| default: | default: |
| fprintf(stderr, "%s: invalid option '%c'\n", argv[0], optopt); | fprintf(stderr, "%s: invalid option '%c'\n", argv[0], c); |
| usage(argv[0]); | usage(argv[0]); |
| break; | break; |
| } | |
| } | } |
| optind++; | |
| } | } |
| if (optind != argc - 1) { | |
| if (optind > argc - 1) { | |
| fprintf(stderr, "%s: file not specified\n", argv[0]); | fprintf(stderr, "%s: file not specified\n", argv[0]); |
| usage(argv[0]); | usage(argv[0]); |
| } | } |
| raw_filespec_to_process=argv[optind]; | |
| raw_filespec_to_process=argv[optind++]; | args_skip=optind; |
| } | } |
| #ifdef WIN32 | #ifdef WIN32 |
| Line 754 int main(int argc, char *argv[]) { | Line 786 int main(int argc, char *argv[]) { |
| int content_length=strlen(buf); | int content_length=strlen(buf); |
| // prepare header | // prepare header |
| SAPI::add_header_attribute(SAPI_info, "content-type", "text/plain"); | // capitalized headers are used for preventing malloc during capitalization |
| SAPI::add_header_attribute(SAPI_info, HTTP_CONTENT_TYPE_CAPITALIZED, "text/plain"); | |
| // don't use 'format' function because it calls malloc | |
| 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(SAPI_info, "content-length", content_length_cstr); | SAPI::add_header_attribute(SAPI_info, HTTP_CONTENT_LENGTH_CAPITALIZED, content_length_cstr); |
| // send header | // send header |
| SAPI::send_header(SAPI_info); | SAPI::send_header(SAPI_info); |