Diff for /parser3/src/targets/cgi/parser3.C between versions 1.108 and 1.192

version 1.108, 2001/09/04 19:05:04 version 1.192, 2002/08/14 09:20:53
Line 1 Line 1
 /** @file  /** @file
         Parser: scripting and CGI main.          Parser: scripting and CGI main.
   
         Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com)          Copyright(c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com)
           Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
         Author: Alexander Petrosyan <paf@design.ru>(http://design.ru/paf)  
 */  */
 static const char *RCSId="$Id$";   
   static const char* IDENT_PARSER3_C="$Date$";
   
 #include "pa_config_includes.h"  #include "pa_config_includes.h"
   
 #ifdef WIN32  #if _MSC_VER
 #       include <windows.h>  #       include <new.h>
   #       include <crtdbg.h>
 #endif  #endif
   
 #include "pa_sapi.h"  #include "pa_sapi.h"
Line 19  static const char *RCSId="$Id$"; Line 20  static const char *RCSId="$Id$";
 #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
   #       include <windows.h>
   #       include "getopt.h"
   #else
   #       include <getopt.h>
   #endif
   
 //#define DEBUG_POOL_MALLOC  //#define DEBUG_POOL_MALLOC
   //#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
   
   #define REDIRECT_PREFIX "REDIRECT_"
   #define PARSER_CONFIG_ENV_NAME "CGI_PARSER_CONFIG"
   
 /// 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 
   
 const char *argv0;  static const char *argv0;
 Pool pool(0); // global pool [dont describe to doxygen: it confuses it with param names]  static char beside_binary_path[MAX_STRING];
 bool cgi; ///< we were started as CGI?  
   
 #ifdef WIN32  
 /// global system errors into parser exceptions converter  
 static LONG WINAPI TopLevelExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo) {  
         char buf[MAX_STRING];  
         if(ExceptionInfo && ExceptionInfo->ExceptionRecord) {  
                 struct _EXCEPTION_RECORD *er=ExceptionInfo->ExceptionRecord;  
                 snprintf(buf, MAX_STRING, "Exception 0x%X at %p",   
                         er->ExceptionCode,   
                         er->ExceptionAddress);  
         } else   
                 strcpy(buf, "Exception <unknown>");  
           
         PTHROW(0, 0,  
                 0,  
                 buf);  
   
         return EXCEPTION_EXECUTE_HANDLER; // never reached  static Pool *pool; // global pool [dont describe to doxygen: it confuses it with param names]
 }  static bool cgi; ///< we were started as CGI?
 #endif  static bool mail_received=false; ///< we were started with -m option? [asked to parse incoming message to $mail:received]
   
 // SAPI  // SAPI
   
 // appends to parser3.log located beside my binary if openable, to stderr otherwize  static void log(const char *fmt, va_list args) {
 void SAPI::log(Pool& pool, const char *fmt, ...) {  
         bool opened;          bool opened;
         FILE *f=0;          FILE *f=0;
   
         if(argv0) {          // try beside by binary first
                 // beside by binary          char file_spec[MAX_STRING];
                 char file_spec[MAX_STRING];          snprintf(file_spec, MAX_STRING, 
                 strncpy(file_spec, argv0, MAX_STRING-1);  file_spec[MAX_STRING-1]=0; // filespec of my binary                  "%s/parser3.log", beside_binary_path);
                 rsplit(file_spec, '/');  rsplit(file_spec, '\\');// strip filename          f=fopen(file_spec, "at");
                 strcat(file_spec, "/parser3.log");  
                 f=fopen(file_spec, "at");  
         }  
         opened=f!=0;          opened=f!=0;
           // fallback to stderr
         if(!opened)          if(!opened)
                 f=stderr;                  f=stderr;
   
         // prefix          // prefix
         time_t t=time(0);          time_t t=time(0);
         const char *stamp=ctime(&t);          if(const char *stamp=ctime(&t)) { // never saw that
         fprintf(f, "[%.*s] ", strlen(stamp)-1, stamp);                  if(size_t len=strlen(stamp)) // saw once stamp being =""
                           fprintf(f, "[%.*s] ", len-1, stamp);
           }
         // message          // message
     va_list args;  
         va_start(args,fmt);          char buf[MAX_STRING];
         vfprintf(f, fmt, args);          size_t size=vsnprintf(buf, MAX_STRING, fmt, args);
         va_end(args);          remove_crlf(buf, buf+size);
   
           fwrite(buf, size, 1, f);
         // newline          // newline
         fprintf(f, "\n");          fprintf(f, "\n");
   
Line 87  void SAPI::log(Pool& pool, const char *f Line 94  void SAPI::log(Pool& pool, const char *f
                 fflush(f);                  fflush(f);
 }  }
   
 static char *_getenv(const char *name) {  // appends to parser3.log located beside my binary if openable, to stderr otherwize
         char *result=getenv(name);  void SAPI::log(Pool& , const char *fmt, ...) {
         return result && *result ? result : 0;      va_list args;
           va_start(args,fmt);
           ::log(fmt, args);
           va_end(args);
 }  }
   
 const char *SAPI::get_env(Pool& pool, const char *name) {  void SAPI::die(const char *fmt, ...) {
         return _getenv(name);  #ifdef DEBUG_POOL_MALLOC
           extern void log_pool_stats(Pool& pool);
           log_pool_stats(*pool);
   #endif
   
       va_list args;
           va_start(args,fmt);
           // log
   
           // logging is more important than user 
           // she can cancel download, we'd get SIG_PIPE, 
           // nothing would be logged then
           ::log(fmt, args);
   
           // inform user
   
           char body[MAX_STRING];
           int content_length=vsnprintf(body, MAX_STRING, fmt, args);
   
           va_end(args);
   
           // prepare header
           // let's be honest, that's bad we couldn't produce valid output
           SAPI::add_header_attribute(*pool, "status", "500");
           SAPI::add_header_attribute(*pool, "content-type", "text/plain");
           char content_length_cstr[MAX_NUMBER];
           snprintf(content_length_cstr, sizeof(content_length_cstr), "%u", content_length);
           SAPI::add_header_attribute(*pool, "content-length", content_length_cstr);
   
           // send header
           SAPI::send_header(*pool);
   
           // body
           SAPI::send_body(*pool, body, content_length);
   
           exit(1);
   }
   
   const char *SAPI::get_env(Pool& , const char *name) {
           return getenv(name);
   }
   
   const char *const *SAPI::environment(Pool&) {
   #ifdef _MSC_VER
           extern char **_environ;
           return _environ;
   #else
           extern char **environ;
           return environ;
   #endif
 }  }
   
 size_t SAPI::read_post(Pool& pool, char *buf, size_t max_bytes) {  size_t SAPI::read_post(Pool& , char *buf, size_t max_bytes) {
         size_t read_size=0;          size_t read_size=0;
         do {          do {
                 int chunk_size=read(fileno(stdin),                   int 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;
         } while(read_size<max_bytes);          } while(read_size<max_bytes);
Line 109  size_t SAPI::read_post(Pool& pool, char Line 168  size_t SAPI::read_post(Pool& pool, char
         return read_size;          return read_size;
 }  }
   
 void SAPI::add_header_attribute(Pool& pool, const char *key, const char *value) {  void SAPI::add_header_attribute(Pool& , const char *key, const char *value) {
         if(cgi)          if(cgi)
                 printf("%s: %s\n", key, value);                  printf("%s: %s\n", key, value);
 }  }
   
 /// @todo intelligent cache-control  /// @todo intelligent cache-control
 void SAPI::send_header(Pool& pool) {  void SAPI::send_header(Pool& ) {
         if(cgi) {          if(cgi) {
                 puts("expires: Fri, 23 Mar 2001 09:32:23 GMT");  //              puts("expires: Fri, 23 Mar 2001 09:32:23 GMT");
   
                 // header | body  delimiter                  // header | body  delimiter
                 puts("");                  puts("");
         }          }
 }  }
   
 void SAPI::send_body(Pool& pool, const void *buf, size_t size) {  void SAPI::send_body(Pool& , const void *buf, size_t size) {
         stdout_write(buf, size);          stdout_write(buf, size);
 }  }
   
 //  //
   
 char *full_file_spec(char *file_name) {  static void full_file_spec(const char *file_name, char *buf, size_t buf_size) {
         if(file_name && !strchr(file_name, '/')) {          if(file_name)
                 static char cwd[MAX_STRING];  getcwd(cwd, MAX_STRING);                  if(file_name[0]=='/' 
                 static char buf[MAX_STRING];  #ifdef WIN32
                 snprintf(buf, MAX_STRING, "%s/%s", cwd, file_name);                          || (file_name[0] && file_name[1]==':')
                 return buf;  #endif
         }                          ) 
         return file_name;                          strncpy(buf, file_name, buf_size);
                   else {
                           char cwd[MAX_STRING];  getcwd(cwd, MAX_STRING);
                           snprintf(buf, buf_size, "%s/%s", cwd, file_name);
                   }
           else
                   buf[0]=0;
   #ifdef WIN32
           back_slashes_to_slashes(buf);
   #endif
 }  }
   
 /**  /**
         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 
 */  */
 int main(int argc, char *argv[]) {  static void real_parser_handler(
         argv0=argv[0];                                          const char *filespec_to_process,
                                           const char *request_method, bool header_only) {
         umask(2);          // init socks
           init_socks(*pool);
         // were we started as CGI?  
         cgi=  
                 _getenv("SERVER_SOFTWARE") ||   
                 _getenv("SERVER_NAME") ||   
                 _getenv("GATEWAY_INTERFACE") ||   
                 _getenv("REQUEST_METHOD");  
                   
         if(!cgi) {          // init global classes
                 if(argc<2) {          init_methoded_array(*pool);
                         printf(          // init global variables
                                 "Parser/%s Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com)\n"          pa_globals_init(*pool);
                                 "Author: Alexander Petrosyan <paf@design.ru>(http://design.ru/paf)\n"          
                                 "\n"          if(!filespec_to_process || !*filespec_to_process)
                                 "Usage: %s <file>\n",                  SAPI::die("Parser/%s", PARSER_VERSION);
                                 PARSER_VERSION,           
                                 argv0?argv0:"parser3");          // Request info
                         return 1;          Request::Info request_info;
                 }          char document_root_buf[MAX_STRING];
           if(cgi) {
                   if(const char *env_document_root=SAPI::get_env(*pool, "DOCUMENT_ROOT"))
                           request_info.document_root=env_document_root;
                   else if(const char *path_info=SAPI::get_env(*pool, "PATH_INFO")) {
                           // IIS
                           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;
                           request_info.document_root=document_root_buf;
                   } else
                           throw Exception("parser.runtime",
                                   0,
                                   "CGI: no PATH_INFO defined(in reinventing DOCUMENT_ROOT)");
           } else {
                   full_file_spec("", document_root_buf, sizeof(document_root_buf));
                   request_info.document_root=document_root_buf;
         }          }
           request_info.path_translated=filespec_to_process;
 #ifdef WIN32          request_info.method=request_method ? request_method : "GET";
         setmode(fileno(stdin), _O_BINARY);          const char *query_string=SAPI::get_env(*pool, "QUERY_STRING");
         setmode(fileno(stdout), _O_BINARY);          request_info.query_string=query_string;
         setmode(fileno(stderr), _O_BINARY);          if(cgi) {
                   if(const char *env_request_uri=SAPI::get_env(*pool, "REQUEST_URI"))
                           request_info.uri=env_request_uri;
                   else if(const char *path_info=SAPI::get_env(*pool, "PATH_INFO"))
                           if(query_string) {
                                   char *reconstructed_uri=(char *)pool->malloc(
                                           strlen(path_info)+1/*'?'*/+
                                           strlen(query_string)+1/*0*/);
                                   strcpy(reconstructed_uri, path_info);
                                   strcat(reconstructed_uri, "?");
                                   strcat(reconstructed_uri, query_string);
                                   request_info.uri=reconstructed_uri;
                           } else
                                   request_info.uri=path_info;
                   else
                           throw Exception("parser.runtime",
                                   0,
                                   "CGI: no PATH_INFO defined(in reinventing REQUEST_URI)");
                           
   #ifndef WIN32
                           // they've changed this under IIS5.
                           if(const char *script_name=SAPI::get_env(*pool, "SCRIPT_NAME")) {
                                   size_t script_name_len=strlen(script_name);
                                   size_t uri_len=strlen(request_info.uri);
                                   if(strncmp(request_info.uri,script_name, script_name_len)==0 &&
                                           script_name_len != uri_len) // under IIS they are the same
                                           SAPI::die("CGI: illegal call");
                           }
 #endif  #endif
           } else
         char *filespec_to_process=cgi?_getenv("PATH_TRANSLATED"):argv[1];                  request_info.uri="";
 #ifdef WIN32          
         back_slashes_to_slashes(filespec_to_process);          request_info.content_type=SAPI::get_env(*pool, "CONTENT_TYPE");
           const char *content_length=SAPI::get_env(*pool, "CONTENT_LENGTH");
           request_info.content_length=(content_length?atoi(content_length):0);
           request_info.cookie=SAPI::get_env(*pool, "HTTP_COOKIE");
           request_info.mail_received=mail_received;
   
           // prepare to process request
           Request request(*pool,
                   request_info,
   /*#ifdef _DEBUG
                   String::UL_HTML|String::UL_OPTIMIZE_BIT
   #else*/
                   cgi ? String::UL_HTML|String::UL_OPTIMIZE_BIT : String::UL_AS_IS
   /*#endif*/
                   ,
                   true /* status_allowed */);
           
           const char *config_filespec_cstr;
           char config_filespec_buf[MAX_STRING];
           const char *config_by_env=getenv(PARSER_CONFIG_ENV_NAME);
           if(!config_by_env)
                   config_by_env=getenv(REDIRECT_PREFIX PARSER_CONFIG_ENV_NAME);
           if(config_by_env)
                   config_filespec_cstr=config_by_env;
           else {
                   snprintf(config_filespec_buf, MAX_STRING, 
                           "%s/%s", 
                           beside_binary_path, AUTO_FILE_NAME);
                   config_filespec_cstr=config_filespec_buf;
           }
           
           // process the request
           request.core(
                   config_filespec_cstr, false /*fail_on_read_problem*/,
                   header_only);
           
           //
           done_socks();
           
   #ifdef DEBUG_POOL_MALLOC
           extern void log_pool_stats(Pool& pool);
           log_pool_stats(*pool);
 #endif  #endif
         filespec_to_process=full_file_spec(filespec_to_process);  
   
         const char *request_method=_getenv("REQUEST_METHOD");  #ifdef DEBUG_STRING_APPENDS_VS_EXPANDS
         bool header_only=request_method && strcasecmp(request_method, "HEAD")==0;          SAPI::log(*pool, 
         PTRY { // global try                  "string piece appends=%lu, wcontext_result_size=%lu, string_string_shortcut_economy_closer=%lu, total_alloc_size=%lu", 
                 // must be first in PTRY{}PCATCH                  string_piece_appends,
 #ifdef WIN32                  wcontext_result_size,
                 SetUnhandledExceptionFilter(&TopLevelExceptionFilter);                  string_string_shortcut_economy,
                   total_alloc_size);
 #endif  #endif
   
                 // init socks  }
                 init_socks(pool);  
   
                 // init global classes  
                 init_methoded_array(pool);  
                 // init global variables  
                 pa_globals_init(pool);  
   
                 if(!filespec_to_process)  
                         PTHROW(0, 0,  
                                 0,  
                                 "Parser/%s", PARSER_VERSION);  
   
                 // Request info  static void call_real_parser_handler__do_SEH(
                 Request::Info request_info;                                                                   const char *filespec_to_process,
                 if(cgi) {                                                                   const char *request_method, bool header_only) {
                         if(const char *env_document_root=SAPI::get_env(pool, "DOCUMENT_ROOT"))  #if _MSC_VER && !defined(_DEBUG)
                                 request_info.document_root=env_document_root;          LPEXCEPTION_POINTERS system_exception=0;
                         else if(const char *path_info=SAPI::get_env(pool, "PATH_INFO")) {          __try {
                                 // IIS  #endif
                                 size_t len=strlen(filespec_to_process)-strlen(path_info);                  real_parser_handler(
                                 char *buf=(char *)pool.malloc(len+1);                          filespec_to_process,
                                 memcpy(buf, filespec_to_process, len); buf[len]=0;                          request_method, header_only);
                                 request_info.document_root=buf;                  
                         } else  #if _MSC_VER && !defined(_DEBUG)
                                 PTHROW(0, 0,          } __except (
                   (system_exception=GetExceptionInformation()), 
                   EXCEPTION_EXECUTE_HANDLER) {
                   
                   if(system_exception)
                           if(_EXCEPTION_RECORD *er=system_exception->ExceptionRecord)
                                   throw Exception(0,
                                         0,                                          0,
                                         "CGI: no PATH_INFO defined(in reinventing DOCUMENT_ROOT)");                                          "Exception 0x%08X at 0x%08X", er->ExceptionCode,  er->ExceptionAddress);
                 } else {  
                         static char buf[MAX_STRING];  
                         strncpy(buf, filespec_to_process, MAX_STRING-1); buf[MAX_STRING-1]=0;  
                         if(rsplit(buf, '/') || rsplit(buf, '\\')) // strip filename  
                                 request_info.document_root=buf;  
                         else                          else
                                 request_info.document_root="";                                  throw Exception(0, 0, "Exception <no exception record>");
                 }  
                 request_info.path_translated=filespec_to_process;  
                 request_info.method=request_method ? request_method : "GET";  
                 const char *query_string=SAPI::get_env(pool, "QUERY_STRING");  
                 request_info.query_string=query_string;  
                 if(cgi) {  
                         if(const char *env_request_uri=SAPI::get_env(pool, "REQUEST_URI"))  
                                 request_info.uri=env_request_uri;  
                         else if(const char *path_info=SAPI::get_env(pool, "PATH_INFO"))  
                                 if(query_string) {  
                                         char *reconstructed_uri=(char *)malloc(  
                                                 strlen(path_info)+1/*'?'*/+  
                                                 strlen(query_string)+1/*0*/);  
                                         strcpy(reconstructed_uri, path_info);  
                                         strcat(reconstructed_uri, "?");  
                                         strcat(reconstructed_uri, query_string);  
                                         request_info.uri=reconstructed_uri;  
                                 } else  
                                         request_info.uri=path_info;  
                         else                          else
                                 PTHROW(0, 0,                                  throw Exception(0, 0, "Exception <no exception information>");
                                         0,          }
                                         "CGI: no PATH_INFO defined(in reinventing REQUEST_URI)");  #endif
   }
   
                         if(const char *script_name=SAPI::get_env(pool, "SCRIPT_NAME")) {  #if _MSC_VER
                                 size_t script_name_len=strlen(script_name);  int failed_new(size_t size) {
                                 size_t uri_len=strlen(request_info.uri);          SAPI::die("out of memory in 'new', failed to allocated %u bytes", size);
                                 if(strncmp(request_info.uri,script_name, script_name_len)==0 &&          return 0; // not reached
                                         script_name_len != uri_len) // under IIS they are the same  }
                                         PTHROW(0, 0,  #endif
                                                 0,  
                                                 "CGI: illegal call");  
                         }  
                 } else  
                         request_info.uri=0;  
   
                 request_info.content_type=SAPI::get_env(pool, "CONTENT_TYPE");  #ifdef HAVE_SET_NEW_HANDLER
                 const char *content_length=SAPI::get_env(pool, "CONTENT_LENGTH");  static void failed_new() {
                 request_info.content_length=(content_length?atoi(content_length):0);      SAPI::die("out of memory in 'new'");
                 request_info.cookie=SAPI::get_env(pool, "HTTP_COOKIE");  }
                 request_info.user_agent=SAPI::get_env(pool, "HTTP_USER_AGENT");  
   
                 // prepare to process request  
                 Request request(pool,  
                         request_info,  
                         cgi ? String::UL_USER_HTML : String::UL_AS_IS  
                         );  
                   
                 // some root-controlled location  
 #ifdef SYSCONFDIR  
                 const char *root_auto_path=SYSCONFDIR;  
 #else  
 #       ifdef WIN32  
                 // c:\windows  
                 static char root_auto_path[MAX_STRING];  
                 GetWindowsDirectory(root_auto_path, MAX_STRING);  
 #       else  
                 #error must be compiled either configure/make or MSVC++  
 #       endif  
 #endif  #endif
                   
   static void usage(const char *program) {
           printf(
                   "Parser/%s Copyright(c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com)\n"
                   "Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)\n"
                   "\n"
                   "Usage: %s [options] file\n"
                   "Options are:\n"
   #ifdef WITH_MAILRECEIVE
                   "    -m  Parse mail, put received letter to $mail:received\n"
   #endif
                   "    -h  Display usage information (this message)\n"
                   , PARSER_VERSION, 
                   program);
           exit(EINVAL);
   }
   
   int main(int argc, char *argv[]) {
           Pool_storage global_pool_storage;
           Pool global_pool(&global_pool_storage);
           pool=&global_pool;
   
   #ifdef DEBUG_MAILRECEIVE
           if(FILE *fake_in=fopen(DEBUG_MAILRECEIVE, "rt")) {
                   dup2(fake_in->_file, 0/*STDIN_FILENO*/);
           }
   #endif
   
   #ifdef _DEBUG
   //      _crtBreakAlloc=33112;
   #endif
   //      _asm int 3;
           {
                   argv0=argv[0];
                 // beside by binary                  // beside by binary
                 static char site_auto_path[MAX_STRING];                  // @todo full path, not ./!
                 strncpy(site_auto_path, argv0, MAX_STRING-1);  site_auto_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(site_auto_path, '/') ||                           rsplit(beside_binary_path, '/') || 
                         rsplit(site_auto_path, '\\'))) { // strip filename                          rsplit(beside_binary_path, '\\'))) { // strip filename
                         // no path, just filename                          // no path, just filename
                         site_auto_path[0]='.'; site_auto_path[1]=0;                          beside_binary_path[0]='.'; beside_binary_path[1]=0;
                 }                  }
                           }
                 // process the request  
                 request.core(  
                         root_auto_path, false,  
                         site_auto_path, false,  
                         header_only);  
   
                 //          umask(2);
                 done_socks();  
   
 #ifdef DEBUG_POOL_MALLOC          // were we started as CGI?
                 extern void log_pool_stats(Pool& pool);          cgi=
                 log_pool_stats(pool);                  getenv("SERVER_SOFTWARE") || 
 #endif                  getenv("SERVER_NAME") || 
                   getenv("GATEWAY_INTERFACE") || 
                   getenv("REQUEST_METHOD");
           
           char *raw_filespec_to_process;
           if(cgi) 
                   raw_filespec_to_process=getenv("PATH_TRANSLATED");
           else {
                   optind = 1;
                   opterr = 0;
                   int c;
                   while((c = getopt(argc, argv, "h"
   #ifdef WITH_MAILRECEIVE
                           "m"
   #endif
                           )) > 0) {
                           switch (c) {
                           case 'h':
                                   usage(argv[0]);
                                   break;
   #ifdef WITH_MAILRECEIVE
                           case 'm':
                                   mail_received=true;
                                   break;
   #endif
                           default:
                                   fprintf(stderr, "%s: invalid option '%c'\n", argv[0], optopt);
                                   usage(argv[0]);
                                   break;
                           }
                   }
                   if (optind != argc - 1) {
                           fprintf(stderr, "%s: file not specified\n", argv[0]);
                           usage(argv[0]);
                   }
                   
                   raw_filespec_to_process=argv[optind++];
           }
   
                 // must be last in PTRY{}PCATCH  
 #ifdef WIN32  #ifdef WIN32
                 SetUnhandledExceptionFilter(0);          setmode(fileno(stdin), _O_BINARY);
           setmode(fileno(stdout), _O_BINARY);
           setmode(fileno(stderr), _O_BINARY);
 #endif  #endif
   
 #ifndef WIN32  #if _MSC_VER
                 //           _set_new_handler(failed_new);
                 if(!cgi)  
                         SAPI::send_body(pool, "\n", 1);  #ifdef _DEBUG
           // Get current flag
           int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
   
           // Turn on leak-checking bit
           tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
   
           // Set flag to the new value
           _CrtSetDbgFlag( tmpFlag );
   //      _CrtSetBreakAlloc(471);
   
 #endif  #endif
   
                 // successful finish  
                 return 0;  
         } PCATCH(e) { // global problem   
                 // must be first in PCATCH{}  
 #ifdef WIN32  
                 SetUnhandledExceptionFilter(0);  
 #endif  #endif
   
   #ifdef HAVE_SET_NEW_HANDLER
           std::set_new_handler(failed_new);
   #endif
   
           char filespec_to_process[MAX_STRING];
           full_file_spec(raw_filespec_to_process, filespec_to_process, sizeof(filespec_to_process));
   
           const char *request_method=getenv("REQUEST_METHOD");
           bool header_only=request_method && strcasecmp(request_method, "HEAD")==0;
   
           try { // global try
                   call_real_parser_handler__do_SEH(
                           filespec_to_process,
                           request_method, header_only);
           } 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();                  SAPI::die("exception in request exception handler: %s", e.comment());
                 // log it  #ifndef _DEBUG
                 SAPI::log(pool, "exception in request exception handler: %s", body);          } catch(...) { 
                   SAPI::die("<unknown exception>");
                 //  #endif
                 int content_length=strlen(body);          }
           
                 // prepare header  
                 SAPI::add_header_attribute(pool, "content-type", "text/plain");  
                 char content_length_cstr[MAX_NUMBER];  
                 snprintf(content_length_cstr, MAX_NUMBER, "%u", content_length);  
                 SAPI::add_header_attribute(pool, "content-length", content_length_cstr);  
   
                 // send header  
                 SAPI::send_header(pool);  
   
                 // body  
                 if(!header_only)  
                         SAPI::send_body(pool, body, content_length);  
   
 #ifndef WIN32  #ifndef WIN32
                 //           // 
                 if(!cgi)          if(!cgi)
                         SAPI::send_body(pool, "\n", 1);                  SAPI::send_body(*pool, "\n", 1);
 #endif  #endif
   //_asm int 3;
                 // unsuccessful finish          return 0;
                 return 1;  
         }  
         PEND_CATCH  
 }  }

Removed from v.1.108  
changed lines
  Added in v.1.192


E-mail: