Diff for /parser3/src/targets/cgi/parser3.C between versions 1.216.2.17 and 1.273

version 1.216.2.17, 2003/02/26 11:29:59 version 1.273, 2016/11/27 23:42:26
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-2015 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"
   
 #if _MSC_VER  
 #       include <crtdbg.h>  
 #endif  
   
 #include "pa_sapi.h"  #include "pa_sapi.h"
 #include "classes.h"  #include "classes.h"
 #include "pa_common.h"  #include "pa_common.h"
 #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 "pa_vconsole.h"
   
 #ifdef WIN32  #ifdef _MSC_VER
 #       include <windows.h>  #include <crtdbg.h>
 #       include "getopt.h"  #include <windows.h>
 #else  #include <direct.h>
 #       include <getopt.h>  
 #endif  #endif
   
 //#define DEBUG_POOL_MALLOC  // defines
 //#define DEBUG_MAILRECEIVE "mailreceive.eml"  
   // 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
   
 // consts  // consts
   
 #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
   
 static const char* argv0;  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 bool force_header_output=false;  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]
   
 // for signal handlers  // for signal handlers
 Request *request=0;  Request *request=0;
   Request_info *request_info=0;
   bool execution_canceled=false;
   
 // SAPI  // SAPI
   
Line 57  static void log(const char* fmt, va_list Line 64  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(!(rsplit(beside_config_path, '/') || rsplit(beside_config_path, '\\'))) { // strip filename
                         rsplit(beside_config_path, '/') ||   
                         rsplit(beside_config_path, '\\'))) { // strip filename  
                         // no path, just filename                          // no path, just filename
                         beside_config_path[0]='.'; beside_config_path[1]=0;                          beside_config_path[0]='.'; beside_config_path[1]=0;
                 }                  }
   
                 char file_spec[MAX_STRING];                  char file_spec[MAX_STRING];
                 snprintf(file_spec, MAX_STRING,                   snprintf(file_spec, MAX_STRING, "%s/parser3.log", beside_config_path);
                         "%s/parser3.log", beside_config_path);  
                 f=fopen(file_spec, "at");                  f=fopen(file_spec, "at");
                 opened=f!=0;                  opened=f!=0;
         }          }
Line 84  static void log(const char* fmt, va_list Line 100  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);
Line 102  static void log(const char* fmt, va_list Line 126  static void log(const char* fmt, va_list
                 fflush(f);                  fflush(f);
 }  }
   
 // appends to parser3.log located beside my binary if openable, to stderr otherwize  #ifdef PA_DEBUG_CGI_ENTRY_EXIT
 void SAPI::log(SAPI_Info&, const char* fmt, ...) {  static void log(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, ...) {  
         //_asm int 3;  
 #ifdef DEBUG_POOL_MALLOC  
         extern void log_pool_stats(Pool& pool);  
         log_pool_stats(SAPI_info);  
 #endif  #endif
   
     va_list args;  // appends to parser3.log located beside my binary if openable, to stderr otherwize
   void SAPI::log(SAPI_Info&, const char* fmt, ...) {
           va_list args;
         va_start(args,fmt);          va_start(args,fmt);
         // log  
   
         // logging is more important than user   
         // she can cancel download, we'd get SIGPIPE,   
         // nothing would be logged then  
         ::log(fmt, args);          ::log(fmt, args);
           va_end(args);
   }
   
   static void die_or_abort(const char* fmt, va_list args, bool write_core) {
         // inform user          // inform user
   
         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(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 147  void SAPI::die(const char* fmt, ...) { Line 165  void SAPI::die(const char* fmt, ...) {
         // body          // body
         SAPI::send_body(SAPI_info, 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) {
 #ifdef WIN32  #ifdef WIN32
         //_asm int 3;                  // IIS with abort failes to show STDOUT, it just barks "abnormal program termination"
         // IIS with abort failes to show STDOUT, it just barks "abnormal program termination"                  exit(1);
         exit(1);  
 #else  #else
         // exit & try to produce core dump                  abort();
         abort();  
 #endif  #endif
           } else
                   exit(1);
   }
   
   void SAPI::die(const char* fmt, ...) {
           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);
           die_or_abort(fmt, args, false /*write core?*/);
   //      va_end(args);
 }  }
   
 char* SAPI::get_env(Pool& pool, SAPI_Info& , const char* name) {  void SAPI::abort(const char* fmt, ...) {
           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);
           die_or_abort(fmt, args, true /*write core?*/);
   //      va_end(args);
   }
   
   char* SAPI::Env::get(SAPI_Info& , const char* name) {
         if(char *local=getenv(name))          if(char *local=getenv(name))
                 return pool.copy(local);                  return pa_strdup(local);
         else          else
                 return 0;                  return 0;
 }  }
   
 const char* const *SAPI::environment(SAPI_Info&, Pool&) {  const char* const *SAPI::Env::get(SAPI_Info&) {
 #ifdef _MSC_VER  #ifdef _MSC_VER
         extern char **_environ;          extern char **_environ;
         return _environ;          return _environ;
Line 177  const char* const *SAPI::environment(SAP Line 223  const char* const *SAPI::environment(SAP
 size_t SAPI::read_post(SAPI_Info& , 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 {
                 ssize_t 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;
                 read_size+=chunk_size;                  read_size+=chunk_size;
Line 188  size_t SAPI::read_post(SAPI_Info& , char Line 233  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 || force_header_output)          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  
 void SAPI::send_header(SAPI_Info& ) {  void SAPI::send_header(SAPI_Info& ) {
         if(cgi || force_header_output) {          if(cgi) {
 //              puts("expires: Fri, 23 Mar 2001 09:32:23 GMT");  
   
                 // header | body  delimiter  
                 puts("");                  puts("");
         }          }
 }  }
   
 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);
 }  }
   
 //  
   
 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]=='/' 
Line 215  static void full_file_spec(const char* f Line 254  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 228  static void full_file_spec(const char* f Line 267  static void full_file_spec(const char* f
 }  }
   
 static void log_signal(const char* signal_name) {  static void log_signal(const char* signal_name) {
         SAPI::log(SAPI_info, request? "%s received. uri=%s, qs=%s"          if(request_info)
                 :"%s received. no request being processed",                   SAPI::log(SAPI_info, "%s received while %s. uri=%s, method=%s, cl=%u",
                 signal_name,                          signal_name,
                 request && request->request_info.uri?request->request_info.uri:"-",                          request ? "executing code" : "reading data",
                 request && request->request_info.query_string?request->request_info.query_string:"-");                          request_info->uri,
                           request_info->method,
                           request_info->content_length);
           else
                   SAPI::log(SAPI_info, "%s received before or after processing request",
                           signal_name);
 }  }
   
 #ifdef SIGUSR1  #ifdef SIGUSR1
Line 242  static void SIGUSR1_handler(int /*sig*/) Line 286  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)          if(request)
                 request->interrupt();                  sigpipe=request->main_class.get_element(sigpipe_name);
           if(sigpipe && sigpipe->as_bool())
                   log_signal(SIGPIPE_NAME);
   
           execution_canceled=true;
           if(request)
                   request->set_interrupted(true);
   }
   #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  #endif
   
   
   class RequestController {
   public:
           RequestController(Request* r){
                   ::request=r;
           }
           ~RequestController(){
                   ::request=0;
           }
   };
   
   
 /**  /**
 main workhorse  main workhorse
   
   @todo     @todo
                 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* request_method, bool header_only) {
                                         const char* filespec_to_process,  
                                         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();
                   
         // request pool, must be different ptr from global [used in VStateless_class.add_method]  
         Pool request_pool;  
   
         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 285  static void real_parser_handler( Line 382  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, "CGI: no PATH_INFO defined(in reinventing DOCUMENT_ROOT)");
                                 Exception::undefined_source,  
                                 "CGI: no PATH_INFO defined(in reinventing DOCUMENT_ROOT)");  
         } else {          } else {
                 full_file_spec("", document_root_buf, sizeof(document_root_buf));                  full_file_spec("", document_root_buf, sizeof(document_root_buf));
                 request_info.document_root=document_root_buf;                  request_info.document_root=document_root_buf;
         }          }
         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 305  static void real_parser_handler( Line 404  static void real_parser_handler(
                 if(!script_name)                  if(!script_name)
                                 SAPI::die("CGI: illegal call (missing SCRIPT_NAME)");                                  SAPI::die("CGI: illegal call (missing SCRIPT_NAME)");
   
                 const char* env_request_uri=getenv("REQUEST_URI");                  const char* env_request_uri=request_info.strip_absolute_uri(getenv("REQUEST_URI"));
                 if(env_request_uri)                  if(env_request_uri)
                         request_info.uri=env_request_uri;                          request_info.uri=env_request_uri;
                 else                   else 
                         if(query_string) {                          if(query_string) {
                                 CharPtr reconstructed_uri(new char[                                  char* reconstructed_uri=new(PointerFreeGC) char[strlen(path_info) + 1/*'?'*/+ strlen(query_string) + 1/*0*/];
                                         strlen(path_info)+1/*'?'*/+  
                                         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);
Line 336  static void real_parser_handler( Line 433  static void real_parser_handler(
                         */                          */
                         size_t script_name_len=strlen(script_name);                          size_t script_name_len=strlen(script_name);
                         size_t uri_len=strlen(env_request_uri);                          size_t uri_len=strlen(env_request_uri);
                         if(strncmp(env_request_uri, script_name, script_name_len)==0 &&                          if(strncmp(env_request_uri, script_name, script_name_len)==0 && script_name_len != uri_len) // under IIS they are the same
                                 script_name_len != uri_len) // under IIS they are the same  
                                 SAPI::die("CGI: illegal call (1)");                                  SAPI::die("CGI: illegal call (1)");
                 } else { // seen on IIS5                  } else { // seen on IIS5
                         /*                          /*
Line 365  static void real_parser_handler( Line 461  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
           ::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          // prepare to process request
         Request request(request_pool, SAPI_info,           Request request(SAPI_info, request_info, cgi ? String::Language(String::L_HTML|String::L_OPTIMIZE_BIT) : String::L_AS_IS);
                 request_info,  
 /*#ifdef _DEBUG          {
                 String::UL_HTML|String::UL_OPTIMIZE_BIT                  // get ::request ptr for signal handlers
 #else*/                  RequestController rc(&request);
                 cgi ? String::UL_HTML|String::UL_OPTIMIZE_BIT : String::UL_AS_IS  
 /*#endif*/                  char config_filespec_buf[MAX_STRING];
                 ,                  if(!config_filespec_cstr) {
                 true /* status_allowed */);                          const char* config_by_env=getenv(PARSER_CONFIG_ENV_NAME);
                           if(!config_by_env)
         // get request ptr for signal handlers                                  config_by_env=getenv(REDIRECT_PREFIX PARSER_CONFIG_ENV_NAME);
         ::request=&request;                          if(config_by_env)
                                   config_filespec_cstr=config_by_env;
         char config_filespec_buf[MAX_STRING];                          else {
         if(!config_filespec_cstr) {                                  // beside by binary
                 const char* config_by_env=getenv(PARSER_CONFIG_ENV_NAME);                                  char beside_binary_path[MAX_STRING];
                 if(!config_by_env)                                  strncpy(beside_binary_path, argv0, MAX_STRING-1);  beside_binary_path[MAX_STRING-1]=0; // filespec of my binary
                         config_by_env=getenv(REDIRECT_PREFIX PARSER_CONFIG_ENV_NAME);                                  if(!(rsplit(beside_binary_path, '/') || rsplit(beside_binary_path, '\\'))) { // strip filename
                 if(config_by_env)                                          // no path, just filename
                         config_filespec_cstr=config_by_env;                                          // @todo full path, not ./!
                 else {                                          beside_binary_path[0]='.'; beside_binary_path[1]=0;
                         // beside by binary                                  }
                         char beside_binary_path[MAX_STRING];                                  snprintf(config_filespec_buf, MAX_STRING, "%s/%s", beside_binary_path, AUTO_FILE_NAME);
                         strncpy(beside_binary_path, argv0, MAX_STRING-1);  beside_binary_path[MAX_STRING-1]=0; // filespec of my binary                                  config_filespec_cstr=config_filespec_buf;
                         if(!(                                  fail_on_config_read_problem=entry_exists(config_filespec_cstr);
                                 rsplit(beside_binary_path, '/') ||   
                                 rsplit(beside_binary_path, '\\'))) { // strip filename  
                                 // no path, just filename  
                                 // @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);  
                 }                  }
                   
                   // 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();
           
 #ifdef DEBUG_POOL_MALLOC  
         extern void log_pool_stats(Pool& pool);  
         log_pool_stats(request_pool);  
 #endif  
 }  }
   
 #if _MSC_VER && !defined(_DEBUG)  #ifdef PA_SUPPRESS_SYSTEM_EXCEPTION
 #       define PA_USE___TRY  static const Exception call_real_parser_handler__do_PEH_return_it(const char* filespec_to_process, const char* request_method, bool header_only){
 struct Parser_executed {          try {
         bool with_system_exception;                  real_parser_handler(filespec_to_process, request_method, header_only);
         LPEXCEPTION_POINTERS system_exception;          } catch(const Exception& e) {
 };                  return e;
 #endif          }
   
 static           return Exception();
 #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(  
                         filespec_to_process,  
                         request_method, header_only);  
                   
 #ifdef PA_USE___TRY  
         } __except (  
                 (result.system_exception=GetExceptionInformation()),   
                 EXCEPTION_EXECUTE_HANDLER) {  
                 //_asm int 3;  
                 result.with_system_exception=true;  
         }  
         return result;  
 #endif  
 }  }
   
 static void call_real_parser_handler__do_SEH(  static void call_real_parser_handler__supress_system_exception(const char* filespec_to_process, const char* request_method, bool header_only){
                                                                  const char* filespec_to_process,          Exception parser_exception;
                                                                  const char* request_method, bool header_only) {          LPEXCEPTION_POINTERS system_exception=0;
 #ifdef PA_USE___TRY  
         Parser_executed executed=          __try {
 #endif                  parser_exception=call_real_parser_handler__do_PEH_return_it(filespec_to_process, request_method, header_only);
                 call_real_parser_handler__do_SEH_return_it(filespec_to_process,           } __except (
                         request_method, header_only);                  (system_exception=GetExceptionInformation()), 
                   EXCEPTION_EXECUTE_HANDLER) 
 #ifdef PA_USE___TRY          {
         if(executed.with_system_exception)  
                 if(executed.system_exception)                  if(system_exception)
                         if(_EXCEPTION_RECORD *er=executed.system_exception->ExceptionRecord)                          if(_EXCEPTION_RECORD *er=system_exception->ExceptionRecord)
                                 throw Exception(Exception::undefined_type,                                  throw Exception("system", 0, "0x%08X at 0x%08X", er->ExceptionCode,  er->ExceptionAddress);
                                         Exception::undefined_source,  
                                         "Exception 0x%08X at 0x%08X", er->ExceptionCode,  er->ExceptionAddress);  
                         else                          else
                                 throw Exception(Exception::undefined_type,                                   throw Exception("system", 0, "<no exception record>");
                                         Exception::undefined_source,   
                                         "Exception <no exception record>");  
                 else                  else
                         throw Exception(Exception::undefined_type,                           throw Exception("system", 0, "<no exception information>");
                                 Exception::undefined_source,           }
                                 "Exception <no exception information>");  
 #endif          if(parser_exception)
                   throw Exception(parser_exception);
 }  }
   
   #define REAL_PARSER_HANDLER call_real_parser_handler__supress_system_exception
   #else
   #define REAL_PARSER_HANDLER real_parser_handler
   #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-2015 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 497  static void usage(const char* program) { Line 574  static void usage(const char* program) {
                 "    -m              Parse mail, put received letter to $mail:received\n"                  "    -m              Parse mail, put received letter to $mail:received\n"
 #endif  #endif
                 "    -f config_file  Use this config file (/path/to/auto.p)\n"                  "    -f config_file  Use this config file (/path/to/auto.p)\n"
                 "    -H              Output CGI header\n"                  "    -h              Display usage information (this message)\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[]) {
   #ifdef PA_DEBUG_CGI_ENTRY_EXIT
           log("main: entry");
   #endif
   
   #ifndef PA_DEBUG_DISABLE_GC
           GC_java_finalization=0;
           // Dont collect unless explicitly requested 
           // this is quicker (~30% ), but less memory-efficient(~8%)
           // so deciding for speed
           GC_dont_gc=1; 
   #endif
   
 #ifdef SIGUSR1  #ifdef SIGUSR1
     if(signal(SIGUSR1, SIGUSR1_handler)==SIG_ERR)      if(signal(SIGUSR1, SIGUSR1_handler)==SIG_ERR)
                 SAPI::die("Can not set handler for SIGUSR1");                  SAPI::die("Can not set handler for SIGUSR1");
Line 514  int main(int argc, char *argv[]) { Line 602  int main(int argc, char *argv[]) {
                 SAPI::die("Can not set handler for SIGPIPE");                  SAPI::die("Can not set handler for SIGPIPE");
 #endif  #endif
   
           argv_all=argv;
 #ifdef DEBUG_MAILRECEIVE  
         if(FILE *fake_in=fopen(DEBUG_MAILRECEIVE, "rt")) {  
                 dup2(fake_in->_file, 0/*STDIN_FILENO*/);  
         }  
 #endif  
   
 #ifdef _DEBUG  
         //_crtBreakAlloc=4042;  
 #endif  
         //_asm int 3;  
         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("GATEWAY_INTERFACE") || getenv("REQUEST_METHOD")) && !getenv("PARSER_VERSION");
                 getenv("SERVER_SOFTWARE") ||   
                 getenv("SERVER_NAME") ||   
                 getenv("GATEWAY_INTERFACE") ||   
                 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");
                 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, "hHf:"                          if(carg[0] != '-')
 #ifdef WITH_MAILRECEIVE  
                         "m"  
 #endif  
                         )) > 0) {  
                         switch (c) {  
                         case 'h':  
                                 usage(argv[0]);  
                                 break;  
                         case 'H':  
                                 force_header_output=true;  
                                 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 _MSC_VER
         setmode(fileno(stdin), _O_BINARY);          setmode(fileno(stdin), _O_BINARY);
         setmode(fileno(stdout), _O_BINARY);          setmode(fileno(stdout), _O_BINARY);
         setmode(fileno(stderr), _O_BINARY);          setmode(fileno(stderr), _O_BINARY);
 #endif  #endif
   
 #if _MSC_VER  #if defined(_MSC_VER) && defined(_DEBUG)
   
 #ifdef _DEBUG  
         // Get current flag          // Get current flag
         int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );          int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
   
         // Turn on leak-checking bit          // Turn on leak-checking bit
 //      tmpFlag |= _CRTDBG_LEAK_CHECK_DF;          tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
   
         // Set flag to the new value          // Set flag to the new value
         _CrtSetDbgFlag( tmpFlag );          _CrtSetDbgFlag( tmpFlag );
 //      _CrtSetBreakAlloc(471);  
   
 #endif  
   
           _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
           _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
 #endif  #endif
   
         char filespec_to_process[MAX_STRING];          char filespec_to_process[MAX_STRING];
Line 609  int main(int argc, char *argv[]) { Line 683  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(                  REAL_PARSER_HANDLER(filespec_to_process, request_method, header_only);
                         filespec_to_process,  
                         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
                   char buf[MAX_STRING];
                   snprintf(buf, MAX_STRING, "Unhandled exception %s", e.comment());
                   // log it
                   SAPI::log(SAPI_info, "%s", buf);
   
                   //
                   int content_length=strlen(buf);
   
                   // prepare header
                   // 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];
                   snprintf(content_length_cstr, MAX_NUMBER, "%u", content_length);
                   SAPI::add_header_attribute(SAPI_info, HTTP_CONTENT_LENGTH_CAPITALIZED, 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
         }          }
   
 //      _asm int 3;  #ifdef PA_DEBUG_CGI_ENTRY_EXIT
           log("main: successful return");
   #endif
         return 0;          return 0;
 }  }

Removed from v.1.216.2.17  
changed lines
  Added in v.1.273


E-mail: