Diff for /parser3/src/targets/cgi/parser3.C between versions 1.216.2.30.2.25 and 1.261

version 1.216.2.30.2.25, 2003/04/21 07:49:55 version 1.261, 2012/06/15 09:30:01
Line 1 Line 1
 /** @file  /** @file
         Parser: scripting and CGI main.          Parser: scripting and CGI main.
   
         Copyright(c) 2001-2003 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* IDENT_PARSER3_C="$Date$";  volatile const char * IDENT_PARSER3_C="$Id$";
   
 #include "pa_config_includes.h"  #include "pa_config_includes.h"
   
Line 20  static const char* IDENT_PARSER3_C="$Dat Line 20  static const char* IDENT_PARSER3_C="$Dat
 #include "pa_socks.h"  #include "pa_socks.h"
 #include "pa_version.h"  #include "pa_version.h"
   
   
   
 #ifdef WIN32  #ifdef WIN32
 #       include <windows.h>  #       include <windows.h>
 #       include "getopt.h"  #endif
 #else  
 #       include <getopt.h>  // 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  #endif
   
 //#define DEBUG_MAILRECEIVE "mailreceive.eml"  //#define DEBUG_MAILRECEIVE "mailreceive.eml"
Line 35  static const char* IDENT_PARSER3_C="$Dat Line 39  static const char* IDENT_PARSER3_C="$Dat
   
 #define REDIRECT_PREFIX "REDIRECT_"  #define REDIRECT_PREFIX "REDIRECT_"
 #define PARSER_CONFIG_ENV_NAME "CGI_PARSER_CONFIG"  #define PARSER_CONFIG_ENV_NAME "CGI_PARSER_CONFIG"
   #define PARSER_LOG_ENV_NAME "CGI_PARSER_LOG"
   
 /// 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 
Line 43  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 59  static void log(const char* fmt, va_list Line 67  static void log(const char* fmt, va_list
         bool opened=false;          bool opened=false;
         FILE *f=0;          FILE *f=0;
   
         if(config_filespec_cstr) {          const char* log_by_env=getenv(PARSER_LOG_ENV_NAME);
           if(!log_by_env)
                   log_by_env=getenv(REDIRECT_PREFIX PARSER_LOG_ENV_NAME);
           if(log_by_env) {
                   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];                  char beside_config_path[MAX_STRING];
                 strncpy(beside_config_path, config_filespec_cstr, MAX_STRING-1);  beside_config_path[MAX_STRING-1]=0;                  strncpy(beside_config_path, config_filespec_cstr, MAX_STRING-1);  beside_config_path[MAX_STRING-1]=0;
                 if(!(                  if(!(
Line 86  static void log(const char* fmt, va_list Line 106  static void log(const char* fmt, va_list
         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] [%u] ", (int)len-1, stamp,
                           (unsigned int)getpid()
                           );
         }          }
         // 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)
                   fprintf(f, " [uri=%s, method=%s, cl=%lu]",
                           request_info->uri? request_info->uri: "<unknown>",
                           request_info->method? request_info->method: "<unknown>",
                           request_info->content_length);
           else
                   fputs(" [no request info]", f);
   
         // newline          // newline
         fprintf(f, "\n");          fputs("\n", f);
   
         if(opened)          if(opened)
                 fclose(f);                  fclose(f);
         else          else
                 fflush(f);                  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  // appends to parser3.log located beside my binary if openable, to stderr otherwize
 void SAPI::log(SAPI_Info&, const char* fmt, ...) {  void SAPI::log(SAPI_Info&, const char* fmt, ...) {
Line 113  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 127  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 156  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;
         va_start(args, fmt);  
         die_or_abort(fmt, args, false/*write core?*/);          // 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_end(args);
   
           va_start(args, fmt);
           die_or_abort(fmt, args, false /*write core?*/);
   //      va_end(args);
 }  }
   
 void SAPI::abort(const char* fmt, ...) {  void SAPI::abort(const char* fmt, ...) {
     va_list args;          va_list args;
         va_start(args, fmt);  
         die_or_abort(fmt, args, true/*write core?*/);          // 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_end(args);
   
           va_start(args, fmt);
           die_or_abort(fmt, args, true /*write core?*/);
   //      va_end(args);
 }  }
   
 char* SAPI::get_env(SAPI_Info& , const char* name) {  char* SAPI::get_env(SAPI_Info& , const char* name) {
Line 200  size_t SAPI::read_post(SAPI_Info& , char Line 245  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)          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 214  void SAPI::send_header(SAPI_Info& ) { Line 259  void SAPI::send_header(SAPI_Info& ) {
         }          }
 }  }
   
 void SAPI::send_body(SAPI_Info& , const void *buf, size_t size) {  size_t SAPI::send_body(SAPI_Info& , const void *buf, size_t size) {
         stdout_write(buf, size);          return stdout_write(buf, size);
 }  }
   
 //  //
Line 227  static void full_file_spec(const char* f Line 272  static void full_file_spec(const char* f
                         || 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];
                         snprintf(buf, buf_size, "%s/%s", cwd, file_name);                          snprintf(buf, buf_size, "%s/%s", getcwd(cwd, MAX_STRING) ? cwd : "", file_name);
                 }                  }
         else          else
                 buf[0]=0;                  buf[0]=0;
Line 241  static void full_file_spec(const char* f Line 286  static void full_file_spec(const char* f
   
 static void log_signal(const char* signal_name) {  static void log_signal(const char* signal_name) {
         if(request_info)          if(request_info)
                 SAPI::log(SAPI_info, "%s received while %s. uri=%s, method=%s, qs=%s, cl=%u",                  SAPI::log(SAPI_info, "%s received while %s. uri=%s, method=%s, cl=%u",
                         signal_name,                          signal_name,
                         request?"executing code":"reading data",                          request?"executing code":"reading data",
                         request_info->uri,                          request_info->uri,
                         request_info->method,                          request_info->method,
                         request_info->query_string,  
                         request_info->content_length);                          request_info->content_length);
         else          else
                 SAPI::log(SAPI_info, "%s received before or after processing request",                  SAPI::log(SAPI_info, "%s received before or after processing request",
Line 260  static void SIGUSR1_handler(int /*sig*/) Line 304  static void SIGUSR1_handler(int /*sig*/)
 #endif  #endif
   
 #ifdef SIGPIPE  #ifdef SIGPIPE
   #define SIGPIPE_NAME "SIGPIPE"
   static const String sigpipe_name(SIGPIPE_NAME);
 static void SIGPIPE_handler(int /*sig*/){  static void SIGPIPE_handler(int /*sig*/){
         log_signal("SIGPIPE");          Value* sigpipe=0;
           if(request)
                   sigpipe=request->main_class.get_element(sigpipe_name);
           if(sigpipe && sigpipe->as_bool())
                   log_signal(SIGPIPE_NAME);
   
         execution_canceled=true;          execution_canceled=true;
         if(request)          if(request)
                 request->set_interrupted(true);                  request->set_interrupted(true);
 }  }
 #endif  #endif
   
   #ifdef WIN32
   const char* maybe_reconstruct_IIS_status_in_qs(const char* original) 
   {
           // 404;http://servername/page[?param=value...]
           // ';' should be urlencoded by HTTP standard, so we shouldn't get it from browser 
           // and can consider that as an indication that this is IIS way to report errors
   
           if(original 
                   && isdigit((unsigned char)original[0])
                   && isdigit((unsigned char)original[1])
                   && isdigit((unsigned char)original[2])
                   && original[3]==';') 
           {
                   size_t original_len=strlen(original);
           char* reconstructed=new(PointerFreeGC) char[original_len
                           +12/*IIS-STATUS=&*/
                           +14/*IIS-DOCUMENT=&*/
                           +1];
                   char* cur=reconstructed;
                   memcpy(cur, "IIS-STATUS=", 11);  cur+=11;
                   memcpy(cur, original, 3); cur+=3;
                   *cur++='&';
   
                   const char* qmark_at=strchr(original, '?');
                   memcpy(cur, "IIS-DOCUMENT=", 13);  cur+=13;
                   {
                           size_t value_len=(qmark_at? qmark_at-original: original_len)-4;
                           memcpy(cur, original+4, value_len);  cur+=value_len;
                   }
   
                   if(qmark_at) {
                           *cur++='&';
                           strcpy(cur, qmark_at+1/*skip ? itself*/);
                   } else
                           *cur=0;
   
                   return reconstructed;
           }
           
           return original;
   }
   #endif
   
   
   class RequestController {
   public:
           RequestController(Request* r){
                   ::request=r;
           }
           ~RequestController(){
                   ::request=0;
           }
   };
   
   
 /**  /**
 main workhorse  main workhorse
   
Line 276  main workhorse Line 382  main workhorse
                 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.
 */  */
 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
         pa_init_socks();          pa_socks_init();
           
         // init global variables          // init global variables
         pa_globals_init();          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"
   #ifdef PA_DEBUG_CGI_ENTRY_EXIT
                   " with entry/exit tracing"
   #endif
                   , 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=getenv("DOCUMENT_ROOT"))                  if(const char* env_document_root=getenv("DOCUMENT_ROOT"))
Line 300  static void real_parser_handler( Line 410  static void real_parser_handler(
                         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;
                         request_info.document_root=document_root_buf;                          request_info.document_root=document_root_buf;
                 } else                  } else
                         throw Exception("parser.runtime",                          throw Exception(PARSER_RUNTIME,
                                 0,                                  0,
                                 "CGI: no PATH_INFO defined(in reinventing DOCUMENT_ROOT)");                                  "CGI: no PATH_INFO defined(in reinventing DOCUMENT_ROOT)");
         } else {          } else {
Line 309  static void real_parser_handler( Line 419  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=getenv("QUERY_STRING");          const char* query_string=
   #ifdef WIN32
                   maybe_reconstruct_IIS_status_in_qs
   #endif
                   (getenv("QUERY_STRING"));
         request_info.query_string=query_string;          request_info.query_string=query_string;
         if(cgi) {          if(cgi) {
                 // few absolute obligatory                  // few absolute obligatory
Line 380  static void real_parser_handler( Line 494  static void real_parser_handler(
         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)
                 SAPI::die("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          // prepare to process request
         Request request(SAPI_info,           Request request(SAPI_info, request_info,
                 request_info,                  cgi ? String::Language(String::L_HTML|String::L_OPTIMIZE_BIT) : String::L_AS_IS);
 /*#ifdef _DEBUG  
                 String::L_HTML|String::L_OPTIMIZE_BIT          {
 #else*/                  // get ::request ptr for signal handlers
                 cgi ? String::Language(String::L_HTML|String::L_OPTIMIZE_BIT) : String::L_AS_IS                  RequestController rc(&request);
 /*#endif*/  
                 ,                  char config_filespec_buf[MAX_STRING];
                 true /* status_allowed */);                  if(!config_filespec_cstr) {
                           const char* config_by_env=getenv(PARSER_CONFIG_ENV_NAME);
         // get request ptr for signal handlers                          if(!config_by_env)
         ::request=&request;                                  config_by_env=getenv(REDIRECT_PREFIX PARSER_CONFIG_ENV_NAME);
                           if(config_by_env)
         char config_filespec_buf[MAX_STRING];                                  config_filespec_cstr=config_by_env;
         if(!config_filespec_cstr) {                          else {
                 const char* config_by_env=getenv(PARSER_CONFIG_ENV_NAME);                                  // beside by binary
                 if(!config_by_env)                                  char beside_binary_path[MAX_STRING];
                         config_by_env=getenv(REDIRECT_PREFIX PARSER_CONFIG_ENV_NAME);                                  strncpy(beside_binary_path, argv0, MAX_STRING-1);  beside_binary_path[MAX_STRING-1]=0; // filespec of my binary
                 if(config_by_env)                                  if(!(
                         config_filespec_cstr=config_by_env;                                          rsplit(beside_binary_path, '/') || 
                 else {                                          rsplit(beside_binary_path, '\\'))) { // strip filename
                         // beside by binary                                          // no path, just filename
                         char beside_binary_path[MAX_STRING];                                          // @todo full path, not ./!
                         strncpy(beside_binary_path, argv0, MAX_STRING-1);  beside_binary_path[MAX_STRING-1]=0; // filespec of my binary                                          beside_binary_path[0]='.'; beside_binary_path[1]=0;
                         if(!(                                  }
                                 rsplit(beside_binary_path, '/') ||                                   snprintf(config_filespec_buf, MAX_STRING, 
                                 rsplit(beside_binary_path, '\\'))) { // strip filename                                          "%s/%s", 
                                 // no path, just filename                                          beside_binary_path, AUTO_FILE_NAME);
                                 // @todo full path, not ./!                                  config_filespec_cstr=config_filespec_buf;
                                 beside_binary_path[0]='.'; beside_binary_path[1]=0;                                  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
                   request.core(
                           config_filespec_cstr, fail_on_config_read_problem,
                           header_only);
   
                   // ::request cleared in RequestController desctructor to prevent signal handlers from accessing invalid memory
         }          }
           
         // process the request  
         request.core(  
                 config_filespec_cstr, fail_on_config_read_problem,  
                 header_only);  
   
         // no request [prevent signal handlers from accessing invalid memory]          // finalize global variables
         ::request=0;          pa_globals_done();
           
         //          //
         pa_done_socks();          pa_socks_done();
 }  }
   
 #if _MSC_VER && !defined(_DEBUG)  #ifdef PA_SUPPRESS_SYSTEM_EXCEPTION
 #       define PA_USE___TRY  static const Exception 
 struct Parser_executed {  call_real_parser_handler__do_PEH_return_it(
         bool with_system_exception;          const char* filespec_to_process,
         LPEXCEPTION_POINTERS system_exception;          const char* request_method, bool header_only) 
 };  {
 #endif          try {
   
 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  
                 real_parser_handler(                  real_parser_handler(
                         filespec_to_process,                          filespec_to_process,
                         request_method, header_only);                          request_method, header_only);
                           } catch(const Exception& e) {
 #ifdef PA_USE___TRY                  return e;
         } __except (  
                 (result.system_exception=GetExceptionInformation()),   
                 EXCEPTION_EXECUTE_HANDLER) {  
                 result.with_system_exception=true;  
         }          }
         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(          __try {
                                              const char* filespec_to_process,                  parser_exception=call_real_parser_handler__do_PEH_return_it(
                                              const char* request_method, bool header_only) {                          filespec_to_process,
 #ifdef PA_USE___TRY  
         Parser_executed executed=  
 #endif  
                 call_real_parser_handler__do_SEH_return_it(filespec_to_process,   
                         request_method, header_only);                          request_method, header_only);
           } __except (
 #ifdef PA_USE___TRY                  (system_exception=GetExceptionInformation()), 
         if(executed.with_system_exception)                  EXCEPTION_EXECUTE_HANDLER) 
                 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,                                          0,
                                         "Exception 0x%08X at 0x%08X", er->ExceptionCode,  er->ExceptionAddress);                                          "0x%08X at 0x%08X", er->ExceptionCode,  er->ExceptionAddress);
                         else                          else
                                 throw Exception(0,                                   throw Exception("system", 
                                         0,                                           0, 
                                         "Exception <no exception record>");                                          "<no exception record>");
                 else                  else
                         throw Exception(0,                           throw Exception("system", 
                                 0,                                   0, 
                                 "Exception <no exception information>");                                  "<no exception information>");
 #endif          }
   
           if(parser_exception)
                   throw Exception(parser_exception);
 }  }
   #endif
   
 static void usage(const char* program) {  static void usage(const char* program) {
         printf(          printf(
                 "Parser/%s Copyright(c) 2001-2003 ArtLebedev Group (http://www.artlebedev.com)\n"                  "Parser/%s\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 517  static void usage(const char* program) { Line 633  static void usage(const char* program) {
 }  }
   
 int main(int argc, char *argv[]) {  int main(int argc, char *argv[]) {
   #ifdef PA_DEBUG_CGI_ENTRY_EXIT
           log("main: entry");
   #endif
           //_asm int 3;
         GC_java_finalization=0;          GC_java_finalization=0;
   
 #ifndef PA_DEBUG_DISABLE_GC  #ifndef PA_DEBUG_DISABLE_GC
Line 554  int main(int argc, char *argv[]) { Line 674  int main(int argc, char *argv[]) {
 #endif  #endif
   
 #ifdef _DEBUG  #ifdef _DEBUG
         //_crtBreakAlloc=4042;          //_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 573  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 635  int main(int argc, char *argv[]) { Line 765  int main(int argc, char *argv[]) {
         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
                 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,                          filespec_to_process,
                         request_method, header_only);                          request_method, header_only);
         } 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();  
                 char buf[MAX_STRING];                  char buf[MAX_STRING];
                 snprintf(buf, MAX_STRING, "exception in request exception handler: %s",                  snprintf(buf, MAX_STRING, "Unhandled exception %s",
                         body);                          e.comment());
                 // log it                  // log it
                 SAPI::log(SAPI_info, "%s", buf);                  SAPI::log(SAPI_info, "%s", buf);
   
Line 653  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);
Line 668  int main(int argc, char *argv[]) { Line 803  int main(int argc, char *argv[]) {
                 // unsuccessful finish                  // unsuccessful finish
         }          }
   
   #ifdef PA_DEBUG_CGI_ENTRY_EXIT
           log("main: successful return");
   #endif
         return 0;          return 0;
 }  }

Removed from v.1.216.2.30.2.25  
changed lines
  Added in v.1.261


E-mail: