Diff for /parser3/src/targets/cgi/parser3.C between versions 1.191 and 1.218

version 1.191, 2002/08/05 14:00:42 version 1.218, 2003/07/24 11:31:25
Line 1 Line 1
 /** @file  /** @file
         Parser: scripting and CGI main.          Parser: scripting and CGI main.
   
         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)
 */  */
   
Line 10  static const char* IDENT_PARSER3_C="$Dat Line 10  static const char* IDENT_PARSER3_C="$Dat
 #include "pa_config_includes.h"  #include "pa_config_includes.h"
   
 #if _MSC_VER  #if _MSC_VER
 #       include <new.h>  
 #       include <crtdbg.h>  #       include <crtdbg.h>
 #endif  #endif
   
Line 20  static const char* IDENT_PARSER3_C="$Dat Line 19  static const char* IDENT_PARSER3_C="$Dat
 #include "pa_request.h"  #include "pa_request.h"
 #include "pa_socks.h"  #include "pa_socks.h"
 #include "pa_version.h"  #include "pa_version.h"
 #include "pool_storage.h"  
   
   
 #ifdef WIN32  #ifdef WIN32
 #       include <windows.h>  #       include <windows.h>
Line 29  static const char* IDENT_PARSER3_C="$Dat Line 29  static const char* IDENT_PARSER3_C="$Dat
 #       include <getopt.h>  #       include <getopt.h>
 #endif  #endif
   
 //#define DEBUG_POOL_MALLOC  //#define DEBUG_MAILRECEIVE "mailreceive.eml"
 //#define DEBUG_STRING_APPENDS_VS_EXPANDS  
 //#define DEBUG_MAILRECEIVE "test.eml"  
   
 #ifdef DEBUG_STRING_APPENDS_VS_EXPANDS  
 extern ulong   
         string_piece_appends,   
         wcontext_result_size,  
         total_alloc_size,  
         string_string_shortcut_economy;  
 #endif  
   
 // consts  // consts
   
Line 49  extern ulong Line 39  extern ulong
 /// IIS refuses to read bigger chunks  /// IIS refuses to read bigger chunks
 const size_t READ_POST_CHUNK_SIZE=0x400*0x400; // 1M   const size_t READ_POST_CHUNK_SIZE=0x400*0x400; // 1M 
   
 static const char *argv0;  static const char* argv0;
 static Pool *pool; // global pool [dont describe to doxygen: it confuses it with param names]  static const char* config_filespec_cstr=0;
   static bool fail_on_config_read_problem=true;
   
 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]
   
   // for signal handlers
   Request *request=0;
   Request_info *request_info=0;
   bool execution_canceled=false;
   
 // SAPI  // SAPI
   
 static void log(const char *fmt, va_list args) {  class SAPI_Info{} SAPI_info;
         bool opened;  
   static void log(const char* fmt, va_list args) {
           bool opened=false;
         FILE *f=0;          FILE *f=0;
   
         if(argv0) {          if(config_filespec_cstr) {
                 // beside by binary                  char beside_config_path[MAX_STRING];
                   strncpy(beside_config_path, config_filespec_cstr, MAX_STRING-1);  beside_config_path[MAX_STRING-1]=0;
                   if(!(
                           rsplit(beside_config_path, '/') || 
                           rsplit(beside_config_path, '\\'))) { // strip filename
                           // no path, just filename
                           beside_config_path[0]='.'; beside_config_path[1]=0;
                   }
   
                 char file_spec[MAX_STRING];                  char file_spec[MAX_STRING];
                 strncpy(file_spec, argv0, MAX_STRING-1);  file_spec[MAX_STRING-1]=0; // filespec of my binary                  snprintf(file_spec, MAX_STRING, 
                 rsplit(file_spec, '/');  rsplit(file_spec, '\\');// strip filename                          "%s/parser3.log", beside_config_path);
                 strcat(file_spec, "/parser3.log");  
                 f=fopen(file_spec, "at");                  f=fopen(file_spec, "at");
                   opened=f!=0;
         }          }
         opened=f!=0;          // fallback to stderr
         if(!opened)          if(!opened)
                 f=stderr;                  f=stderr;
   
           // use no memory [so that we could log out-of-memory error]
           setbuf(f, 0); // stderr stream is unbuffered by default, but still...
   
         // prefix          // prefix
         time_t t=time(0);          time_t t=time(0);
         if(const char *stamp=ctime(&t)) { // never saw that          if(const char* stamp=ctime(&t)) { // never saw that
                 if(size_t len=strlen(stamp)) // saw once stamp being =""                  if(size_t len=strlen(stamp)) // saw once stamp being =""
                         fprintf(f, "[%.*s] ", len-1, stamp);                          fprintf(f, "[%.*s] ", len-1, stamp);
         }          }
Line 95  static void log(const char *fmt, va_list Line 105  static void log(const char *fmt, va_list
 }  }
   
 // appends to parser3.log located beside my binary if openable, to stderr otherwize  // appends to parser3.log located beside my binary if openable, to stderr otherwize
 void SAPI::log(Pool& , const char *fmt, ...) {  void SAPI::log(SAPI_Info&, const char* fmt, ...) {
     va_list args;      va_list args;
         va_start(args,fmt);          va_start(args,fmt);
         ::log(fmt, args);          ::log(fmt, args);
         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) {
 #ifdef DEBUG_POOL_MALLOC  
         extern void log_pool_stats(Pool& pool);  
         log_pool_stats(*pool);  
 #endif  
   
     va_list args;  
         va_start(args,fmt);  
         // log          // log
   
         // logging is more important than user           // logging is more important than user 
         // she can cancel download, we'd get SIG_PIPE,           // she can cancel download, we'd get SIGPIPE, 
         // nothing would be logged then          // nothing would be logged then
         ::log(fmt, args);          ::log(fmt, args);
   
Line 122  void SAPI::die(const char *fmt, ...) { Line 125  void SAPI::die(const char *fmt, ...) {
         char body[MAX_STRING];          char body[MAX_STRING];
         int content_length=vsnprintf(body, MAX_STRING, fmt, args);          int content_length=vsnprintf(body, MAX_STRING, fmt, args);
   
         va_end(args);  
   
         // 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(*pool, "status", "500");          SAPI::add_header_attribute(SAPI_info, "status", "500");
         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];          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(*pool, "content-length", content_length_cstr);          SAPI::add_header_attribute(SAPI_info, "content-length", content_length_cstr);
   
         // send header          // send header
         SAPI::send_header(*pool);          SAPI::send_header(SAPI_info);
   
         // body          // body
         SAPI::send_body(*pool, body, content_length);          SAPI::send_body(SAPI_info, body, content_length);
   
           // exit & try to produce core dump[unix] or invoke debugger[Win32 Debug version]
           if(write_core) {
   #if defined(WIN32) && !defined(_DEBUG)
                   // IIS with abort failes to show STDOUT, it just barks "abnormal program termination"
                   exit(1);
   #else
   #if _MSC_VER
                   _asm int 3;
   #endif
                   abort();
   #endif
           } 
           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);
   }
   
         exit(1);  void SAPI::abort(const char* fmt, ...) {
       va_list args;
           va_start(args, fmt);
           die_or_abort(fmt, args, true/*write core?*/);
           va_end(args);
 }  }
   
 const char *SAPI::get_env(Pool& , const char *name) {  char* SAPI::get_env(SAPI_Info& , const char* name) {
         return getenv(name);          if(char *local=getenv(name))
                   return pa_strdup(local);
           else
                   return 0;
 }  }
   
 const char *const *SAPI::environment(Pool&) {  const char* const *SAPI::environment(SAPI_Info&) {
 #ifdef _MSC_VER  #ifdef _MSC_VER
         extern char **_environ;          extern char **_environ;
         return _environ;          return _environ;
Line 155  const char *const *SAPI::environment(Poo Line 186  const char *const *SAPI::environment(Poo
 #endif  #endif
 }  }
   
 size_t SAPI::read_post(Pool& , char *buf, size_t max_bytes) {  size_t SAPI::read_post(SAPI_Info& , char *buf, size_t max_bytes) {
         size_t read_size=0;          size_t read_size=0;
         do {          do {
                 int chunk_size=read(fileno(stdin),                   ssize_t chunk_size=read(fileno(stdin), 
                         buf+read_size, min(READ_POST_CHUNK_SIZE, max_bytes-read_size));                          buf+read_size, min(READ_POST_CHUNK_SIZE, max_bytes-read_size));
                 if(chunk_size<=0)                  if(chunk_size<=0)
                         break;                          break;
Line 168  size_t SAPI::read_post(Pool& , char *buf Line 199  size_t SAPI::read_post(Pool& , char *buf
         return read_size;          return read_size;
 }  }
   
 void SAPI::add_header_attribute(Pool& , const char *key, const char *value) {  void SAPI::add_header_attribute(SAPI_Info& , const char* dont_store_key, const char* dont_store_value) {
         if(cgi)          if(cgi)
                 printf("%s: %s\n", key, value);                  printf("%s: %s\n", dont_store_key, dont_store_value);
 }  }
   
 /// @todo intelligent cache-control  /// @todo intelligent cache-control
 void SAPI::send_header(Pool& ) {  void SAPI::send_header(SAPI_Info& ) {
         if(cgi) {          if(cgi) {
 //              puts("expires: Fri, 23 Mar 2001 09:32:23 GMT");  //              puts("expires: Fri, 23 Mar 2001 09:32:23 GMT");
   
Line 183  void SAPI::send_header(Pool& ) { Line 214  void SAPI::send_header(Pool& ) {
         }          }
 }  }
   
 void SAPI::send_body(Pool& , const void *buf, size_t size) {  void SAPI::send_body(SAPI_Info& , const void *buf, size_t size) {
         stdout_write(buf, size);          stdout_write(buf, size);
 }  }
   
 //  //
   
 static void full_file_spec(const char *file_name, char *buf, size_t buf_size) {  static void full_file_spec(const char* file_name, char *buf, size_t buf_size) {
         if(file_name)          if(file_name)
                 if(file_name[0]=='/'                   if(file_name[0]=='/' 
 #ifdef WIN32  #ifdef WIN32
                         || (file_name[0] && file_name[1]==':')                          || file_name[0] && file_name[1]==':'
 #endif  #endif
                         )                           )
                         strncpy(buf, file_name, buf_size);                                  strncpy(buf, file_name, buf_size);
                 else {                  else {
                         char cwd[MAX_STRING];  getcwd(cwd, MAX_STRING);                          char cwd[MAX_STRING];  getcwd(cwd, MAX_STRING);
                         snprintf(buf, buf_size, "%s/%s", cwd, file_name);                          snprintf(buf, buf_size, "%s/%s", cwd, file_name);
Line 208  static void full_file_spec(const char *f Line 239  static void full_file_spec(const char *f
 #endif  #endif
 }  }
   
   static void log_signal(const char* signal_name) {
           if(request_info)
                   SAPI::log(SAPI_info, "%s received while %s. uri=%s, method=%s, qs=%s, cl=%u",
                           signal_name,
                           request?"executing code":"reading data",
                           request_info->uri,
                           request_info->method,
                           request_info->query_string,
                           request_info->content_length);
           else
                   SAPI::log(SAPI_info, "%s received before or after processing request",
                           signal_name);
   }
   
   #ifdef SIGUSR1
   static void SIGUSR1_handler(int /*sig*/){
           log_signal("SIGUSR1");
   }
   #endif
   
   #ifdef SIGPIPE
   static void SIGPIPE_handler(int /*sig*/){
           log_signal("SIGPIPE");
           execution_canceled=true;
           if(request)
                   request->set_interrupted(true);
   }
   #endif
   
 /**  /**
 main workhorse  main workhorse
   
Line 215  main workhorse Line 275  main workhorse
                 IIS: remove trailing default-document[index.html] from $request.uri.                  IIS: remove trailing default-document[index.html] from $request.uri.
                 to do that we need to consult metabase,                  to do that we need to consult metabase,
                 wich is tested but seems slow.                  wich is tested but seems slow.
                 IIS5 todo find out proper 'illegal call' check   
 */  */
 static void real_parser_handler(  static void real_parser_handler(const char* filespec_to_process,
                                         const char *filespec_to_process,                                  const char* request_method, bool header_only) {
                                         const char *request_method, bool header_only) {  
         // init socks          // init socks
         init_socks(*pool);          pa_init_socks();
                   
         // init global classes  
         init_methoded_array(*pool);  
         // init global variables          // init global variables
         pa_globals_init(*pool);          pa_globals_init();
                   
         if(!filespec_to_process || !*filespec_to_process)          if(!filespec_to_process || !*filespec_to_process)
                 SAPI::die("Parser/%s", PARSER_VERSION);                  SAPI::die("Parser/%s", PARSER_VERSION);
                   
         // Request info          // Request info
         Request::Info request_info;          Request_info request_info;  memset(&request_info, 0, sizeof(request_info));
         char document_root_buf[MAX_STRING];          char document_root_buf[MAX_STRING];
         if(cgi) {          if(cgi) {
                 if(const char *env_document_root=SAPI::get_env(*pool, "DOCUMENT_ROOT"))                  if(const char* env_document_root=getenv("DOCUMENT_ROOT"))
                         request_info.document_root=env_document_root;                          request_info.document_root=env_document_root;
                 else if(const char *path_info=SAPI::get_env(*pool, "PATH_INFO")) {                  else if(const char* path_info=getenv("PATH_INFO")) {
                         // IIS                          // IIS
                         size_t len=min(sizeof(document_root_buf)-1, strlen(filespec_to_process)-strlen(path_info));                          size_t len=min(sizeof(document_root_buf)-1, strlen(filespec_to_process)-strlen(path_info));
                         memcpy(document_root_buf, filespec_to_process, len); document_root_buf[len]=0;                          memcpy(document_root_buf, filespec_to_process, len); document_root_buf[len]=0;
Line 252  static void real_parser_handler( Line 308  static void real_parser_handler(
         }          }
         request_info.path_translated=filespec_to_process;          request_info.path_translated=filespec_to_process;
         request_info.method=request_method ? request_method : "GET";          request_info.method=request_method ? request_method : "GET";
         const char *query_string=SAPI::get_env(*pool, "QUERY_STRING");          const char* query_string=getenv("QUERY_STRING");
         request_info.query_string=query_string;          request_info.query_string=query_string;
         if(cgi) {          if(cgi) {
                 if(const char *env_request_uri=SAPI::get_env(*pool, "REQUEST_URI"))                  // few absolute obligatory
                   const char* path_info=getenv("PATH_INFO");
                   if(!path_info)
                           SAPI::die("CGI: illegal call (missing PATH_INFO)");
                   const char* script_name=getenv("SCRIPT_NAME");
                   if(!script_name)
                                   SAPI::die("CGI: illegal call (missing SCRIPT_NAME)");
   
                   const char* env_request_uri=getenv("REQUEST_URI");
                   if(env_request_uri)
                         request_info.uri=env_request_uri;                          request_info.uri=env_request_uri;
                 else if(const char *path_info=SAPI::get_env(*pool, "PATH_INFO"))                  else 
                         if(query_string) {                          if(query_string) {
                                 char *reconstructed_uri=(char *)pool->malloc(                                  char* reconstructed_uri=new(PointerFreeGC) char[
                                         strlen(path_info)+1/*'?'*/+                                          strlen(path_info)+1/*'?'*/+
                                         strlen(query_string)+1/*0*/);                                          strlen(query_string)+1/*0*/];
                                 strcpy(reconstructed_uri, path_info);                                  strcpy(reconstructed_uri, path_info);
                                 strcat(reconstructed_uri, "?");                                  strcat(reconstructed_uri, "?");
                                 strcat(reconstructed_uri, query_string);                                  strcat(reconstructed_uri, query_string);
                                 request_info.uri=reconstructed_uri;                                  request_info.uri=reconstructed_uri;
                         } else                          } else
                                 request_info.uri=path_info;                                  request_info.uri=path_info;
                 else  
                         throw Exception("parser.runtime",                  if(env_request_uri) { // apache & others stuck to standards
                                 0,                          /*
                                 "CGI: no PATH_INFO defined(in reinventing REQUEST_URI)");                                  http://parser3/env.html?123  =OK
                                                           $request:uri=/env.html?123
 #ifndef WIN32                                  REQUEST_URI='/env.html?123'
                         // they've changed this under IIS5.                                  SCRIPT_NAME='/cgi-bin/parser3'
                         if(const char *script_name=SAPI::get_env(*pool, "SCRIPT_NAME")) {                                  PATH_INFO='/env.html'
                                 size_t script_name_len=strlen(script_name);  
                                 size_t uri_len=strlen(request_info.uri);                                  http://parser3/cgi-bin/parser3/env.html?123 =ERROR
                                 if(strncmp(request_info.uri,script_name, script_name_len)==0 &&                                  $request:uri=/cgi-bin/parser3/env.html?123
                                         script_name_len != uri_len) // under IIS they are the same                                  REQUEST_URI='/cgi-bin/parser3/env.html?123'
                                         SAPI::die("CGI: illegal call");                                  SCRIPT_NAME='/cgi-bin/parser3'
                         }                                  PATH_INFO='/env.html'
 #endif                          */
                           size_t script_name_len=strlen(script_name);
                           size_t uri_len=strlen(env_request_uri);
                           if(strncmp(env_request_uri, script_name, script_name_len)==0 &&
                                   script_name_len != uri_len) // under IIS they are the same
                                   SAPI::die("CGI: illegal call (1)");
                   } else { // seen on IIS5
                           /*
                                   http://nestle/env.html?123 =OK
                                   $request:uri=/env.html?123
                                   REQUEST_URI=''
                                   SCRIPT_NAME='/env.html'
                                   PATH_INFO='/env.html'
   
                                   http://nestle/cgi-bin/parser3.exe/env.html =ERROR
                                   $request:uri=/env.html
                                   REQUEST_URI=''
                                   SCRIPT_NAME='/cgi-bin/parser3.exe'
                                   PATH_INFO='/env.html'
                           */
                           if(strcmp(script_name, path_info)!=0)
                                   SAPI::die("CGI: illegal call (2)");
                   }
         } else          } else
                 request_info.uri="";                  request_info.uri="";
                   
         request_info.content_type=SAPI::get_env(*pool, "CONTENT_TYPE");          request_info.content_type=getenv("CONTENT_TYPE");
         const char *content_length=SAPI::get_env(*pool, "CONTENT_LENGTH");          const char* content_length=getenv("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=getenv("HTTP_COOKIE");
         request_info.mail_received=mail_received;          request_info.mail_received=mail_received;
   
           // get request_info ptr for signal handlers
           ::request_info=&request_info;
           if(execution_canceled)
                   SAPI::die("Execution canceled");
   
         // prepare to process request          // prepare to process request
         Request request(*pool,          Request request(SAPI_info, 
                 request_info,                  request_info,
 /*#ifdef _DEBUG                  cgi ? String::Language(String::L_HTML|String::L_OPTIMIZE_BIT) : String::L_AS_IS,
                 String::UL_HTML|String::UL_OPTIMIZE_BIT  
 #else*/  
                 cgi ? String::UL_HTML|String::UL_OPTIMIZE_BIT : String::UL_AS_IS  
 /*#endif*/  
                 ,  
                 true /* status_allowed */);                  true /* status_allowed */);
           
         const char *config_filespec_cstr;          // get request ptr for signal handlers
           ::request=&request;
   
         char config_filespec_buf[MAX_STRING];          char config_filespec_buf[MAX_STRING];
         const char *config_by_env=getenv(PARSER_CONFIG_ENV_NAME);          if(!config_filespec_cstr) {
         if(!config_by_env)                  const char* config_by_env=getenv(PARSER_CONFIG_ENV_NAME);
                 config_by_env=getenv(REDIRECT_PREFIX PARSER_CONFIG_ENV_NAME);                  if(!config_by_env)
         if(config_by_env)                          config_by_env=getenv(REDIRECT_PREFIX PARSER_CONFIG_ENV_NAME);
                 config_filespec_cstr=config_by_env;                  if(config_by_env)
         else {                          config_filespec_cstr=config_by_env;
         // beside by binary                  else {
         // @todo full path, not ./!                          // 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
                         beside_binary_path[0]='.'; beside_binary_path[1]=0;                                  // @todo full path, not ./!
                                   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;  
         }          }
                   
         // process the request          // process the request
         request.core(          request.core(
                 config_filespec_cstr, false /*fail_on_read_problem*/,                  config_filespec_cstr, fail_on_config_read_problem,
                 header_only);                  header_only);
   
           // no request [prevent signal handlers from accessing invalid memory]
           ::request=0;
                   
         //          //
         done_socks();          pa_done_socks();
           
 #ifdef DEBUG_POOL_MALLOC  
         extern void log_pool_stats(Pool& pool);  
         log_pool_stats(*pool);  
 #endif  
   
 #ifdef DEBUG_STRING_APPENDS_VS_EXPANDS  
         SAPI::log(*pool,   
                 "string piece appends=%lu, wcontext_result_size=%lu, string_string_shortcut_economy_closer=%lu, total_alloc_size=%lu",   
                 string_piece_appends,  
                 wcontext_result_size,  
                 string_string_shortcut_economy,  
                 total_alloc_size);  
 #endif  
   
 }  }
   
 static void call_real_parser_handler__do_SEH(  
                                                                  const char *filespec_to_process,  
                                                                  const char *request_method, bool header_only) {  
 #if _MSC_VER && !defined(_DEBUG)  #if _MSC_VER && !defined(_DEBUG)
         LPEXCEPTION_POINTERS system_exception=0;  #       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 {          __try {
 #endif  #endif
                 real_parser_handler(                  real_parser_handler(
                         filespec_to_process,                          filespec_to_process,
                         request_method, header_only);                          request_method, header_only);
                                   
 #if _MSC_VER && !defined(_DEBUG)  #ifdef PA_USE___TRY
         } __except (          } __except (
                 (system_exception=GetExceptionInformation()),                   (result.system_exception=GetExceptionInformation()), 
                 EXCEPTION_EXECUTE_HANDLER) {                  EXCEPTION_EXECUTE_HANDLER) {
                                   result.with_system_exception=true;
                 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 <no exception record>");  
                         else  
                                 throw Exception(0, 0, "Exception <no exception information>");  
         }          }
           return result;
 #endif  #endif
 }  }
   
 #if _MSC_VER  static void call_real_parser_handler__do_SEH(
 int failed_new(size_t size) {                                               const char* filespec_to_process,
         SAPI::die("out of memory in 'new', failed to allocated %u bytes", size);                                               const char* request_method, bool header_only) {
         return 0; // not reached  #ifdef PA_USE___TRY
 }          Parser_executed executed=
 #endif  #endif
                   call_real_parser_handler__do_SEH_return_it(filespec_to_process, 
                           request_method, header_only);
   
 #ifdef HAVE_SET_NEW_HANDLER  #ifdef PA_USE___TRY
 static void failed_new() {          if(executed.with_system_exception)
     SAPI::die("out of memory in 'new'");                  if(executed.system_exception)
 }                          if(_EXCEPTION_RECORD *er=executed.system_exception->ExceptionRecord)
                                   throw Exception(0,
                                           0,
                                           "Exception 0x%08X at 0x%08X", er->ExceptionCode,  er->ExceptionAddress);
                           else
                                   throw Exception(0, 
                                           0, 
                                           "Exception <no exception record>");
                   else
                           throw Exception(0, 
                                   0, 
                                   "Exception <no exception information>");
 #endif  #endif
   }
   
 static void usage(const char *program) {  static void usage(const char* program) {
         printf(          printf(
                 "Parser/%s Copyright(c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com)\n"                  "Parser/%s Copyright(c) 2001-2003 ArtLebedev Group (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"
                 "Options are:\n"                  "Options are:\n"
 #ifdef WITH_MAILRECEIVE  #ifdef WITH_MAILRECEIVE
                 "    -m  Parse mail, put received letter to $mail:received\n"                  "    -m              Parse mail, put received letter to $mail:received\n"
 #endif  #endif
                 "    -h  Display usage information (this message)\n"                  "    -f config_file  Use this config file (/path/to/auto.p)\n"
                   "    -h              Display usage information (this message)\n"
                 , PARSER_VERSION,                   , PARSER_VERSION, 
                 program);                  program);
         exit(EINVAL);          exit(EINVAL);
 }  }
   
 int main(int argc, char *argv[]) {  int main(int argc, char *argv[]) {
         Pool_storage global_pool_storage;          GC_java_finalization=0;
         Pool global_pool(&global_pool_storage);  
         pool=&global_pool;  #ifndef PA_DEBUG_DISABLE_GC
           // Dont collect unless explicitly requested 
           // this is quicker (~30% ), but less memory-efficient(~8%)
           // so deciding for speed
           GC_dont_gc=1; 
   #endif
   /*
           
           Array<int> test;
           test+=3;
           test+=4;
   //      int a=test.count();
           int i=0;
           scanf("%d", &i);
           int b=test.get(i);
   //      int b=test.get(10);
           printf("%d", b);//test.count());*/
   
   #ifdef SIGUSR1
       if(signal(SIGUSR1, SIGUSR1_handler)==SIG_ERR)
                   SAPI::die("Can not set handler for SIGUSR1");
   #endif
   #ifdef SIGPIPE
       if(signal(SIGPIPE, SIGPIPE_handler)==SIG_ERR)
                   SAPI::die("Can not set handler for SIGPIPE");
   #endif
   
   
 #ifdef DEBUG_MAILRECEIVE  #ifdef DEBUG_MAILRECEIVE
         if(FILE *fake_in=fopen(DEBUG_MAILRECEIVE, "rt")) {          if(FILE *fake_in=fopen(DEBUG_MAILRECEIVE, "rt")) {
Line 421  int main(int argc, char *argv[]) { Line 548  int main(int argc, char *argv[]) {
 #endif  #endif
   
 #ifdef _DEBUG  #ifdef _DEBUG
 //      _crtBreakAlloc=33112;          //_crtBreakAlloc=4042;
 #endif  #endif
 //      _asm int 3;  
         argv0=argv[0];          argv0=argv[0];
   
         umask(2);          umask(2);
Line 436  int main(int argc, char *argv[]) { Line 562  int main(int argc, char *argv[]) {
                 getenv("REQUEST_METHOD");                  getenv("REQUEST_METHOD");
                   
         char *raw_filespec_to_process;          char *raw_filespec_to_process;
         if(cgi)           if(cgi) {
                 raw_filespec_to_process=getenv("PATH_TRANSLATED");                  raw_filespec_to_process=getenv("PATH_TRANSLATED");
         else {                  if(raw_filespec_to_process && !*raw_filespec_to_process)
                           raw_filespec_to_process=0;
           } else {
                 optind = 1;                  optind = 1;
                 opterr = 0;                  opterr = 0;
                 int c;                  int c;
                 while((c = getopt(argc, argv, "h"                  while((c = getopt(argc, argv, "hf:"
 #ifdef WITH_MAILRECEIVE  #ifdef WITH_MAILRECEIVE
                         "m"                          "m"
 #endif  #endif
Line 451  int main(int argc, char *argv[]) { Line 579  int main(int argc, char *argv[]) {
                         case 'h':                          case 'h':
                                 usage(argv[0]);                                  usage(argv[0]);
                                 break;                                  break;
                           case 'f':
                                   config_filespec_cstr=optarg;
                                   break;
 #ifdef WITH_MAILRECEIVE  #ifdef WITH_MAILRECEIVE
                         case 'm':                          case 'm':
                                 mail_received=true;                                  mail_received=true;
Line 476  int main(int argc, char *argv[]) { Line 607  int main(int argc, char *argv[]) {
         setmode(fileno(stderr), _O_BINARY);          setmode(fileno(stderr), _O_BINARY);
 #endif  #endif
   
 #if _MSC_VER  #if defined(_MSC_VER) && defined(_DEBUG)
         _set_new_handler(failed_new);  
   
 #ifdef _DEBUG  
         // Get current flag          // Get current flag
         int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );          int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
   
Line 488  int main(int argc, char *argv[]) { Line 616  int main(int argc, char *argv[]) {
   
         // Set flag to the new value          // Set flag to the new value
         _CrtSetDbgFlag( tmpFlag );          _CrtSetDbgFlag( tmpFlag );
 //      _CrtSetBreakAlloc(471);  //      _CrtSetBreakAlloc(61);
   
 #endif  
   
 #endif  
   
 #ifdef HAVE_SET_NEW_HANDLER          _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
         std::set_new_handler(failed_new);          _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
 #endif  #endif
   
         char filespec_to_process[MAX_STRING];          char filespec_to_process[MAX_STRING];
         full_file_spec(raw_filespec_to_process, filespec_to_process, sizeof(filespec_to_process));          full_file_spec(raw_filespec_to_process, filespec_to_process, sizeof(filespec_to_process));
   
         const char *request_method=getenv("REQUEST_METHOD");          const char* request_method=getenv("REQUEST_METHOD");
         bool header_only=request_method && strcasecmp(request_method, "HEAD")==0;          bool header_only=request_method && strcasecmp(request_method, "HEAD")==0;
   
         try { // global try          try { // global try
Line 512  int main(int argc, char *argv[]) { Line 636  int main(int argc, char *argv[]) {
                 // 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();
                   char buf[MAX_STRING];
                   snprintf(buf, MAX_STRING, "exception in request exception handler: %s",
                           body);
                   // log it
                   SAPI::log(SAPI_info, "%s", buf);
   
                   //
                   int content_length=strlen(buf);
   
                   // prepare header
                   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(SAPI_info, "content-length", content_length_cstr);
   
                   // send header
                   SAPI::send_header(SAPI_info);
   
                   // send body
                   if(!header_only)
                           SAPI::send_body(SAPI_info, buf, content_length);
   
                 SAPI::die("exception in request exception handler: %s", e.comment());                  // unsuccessful finish
 #ifndef _DEBUG  
         } catch(...) {   
                 SAPI::die("<unknown exception>");  
 #endif  
         }          }
           
   
 #ifndef WIN32  
         //   
         if(!cgi)  
                 SAPI::send_body(*pool, "\n", 1);  
 #endif  
 //_asm int 3;  
         return 0;          return 0;
 }  }

Removed from v.1.191  
changed lines
  Added in v.1.218


E-mail: