Diff for /parser3/src/targets/cgi/parser3.C between versions 1.135 and 1.253

version 1.135, 2001/11/16 11:06:08 version 1.253, 2009/08/30 05:29:46
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-2009 ArtLebedev Group (http://www.artlebedev.com)
         Author: Alexander Petrosyan <paf@design.ru>(http://paf.design.ru)          Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
   
         $Id$  
 */  */
   
   static const char * const IDENT_PARSER3_C="$Date$";
   
 #include "pa_config_includes.h"  #include "pa_config_includes.h"
   
 #ifdef WIN32  #if _MSC_VER
 #       include <windows.h>  #       include <crtdbg.h>
 #       include <new.h>  
 #endif  #endif
   
 #include "pa_sapi.h"  #include "pa_sapi.h"
Line 20 Line 19
 #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 XML  #ifdef WIN32
 #include <XalanTransformer/XalanCAPI.h>  #       include <windows.h>
 #endif  #endif
   
 //#define DEBUG_POOL_MALLOC  // defines
   
 // consts  // comment remove me after debugging
   //#define PA_DEBUG_CGI_ENTRY_EXIT       "c:\\parser\\debug-parser3.log"
   
 extern const char *main_RCSIds[];  #if _MSC_VER && !defined(_DEBUG)
 #ifdef USE_SMTP  #       define PA_SUPPRESS_SYSTEM_EXCEPTION
 extern const char *smtp_RCSIds[];  
 #endif  
 extern const char *gd_RCSIds[];  
 extern const char *classes_RCSIds[];  
 extern const char *types_RCSIds[];  
 extern const char *parser3_RCSIds[];  
 #ifdef XML  
 extern const char *xalan_patched_RCSIds[];  
 #endif  
 const char **RCSIds[]={  
         main_RCSIds,  
 #ifdef USE_SMTP  
         smtp_RCSIds,  
 #endif  
         gd_RCSIds,  
         classes_RCSIds,  
         types_RCSIds,  
         parser3_RCSIds,  
 #ifdef XML  
         xalan_patched_RCSIds,  
 #endif  #endif
         0  
 };  //#define DEBUG_MAILRECEIVE "mailreceive.eml"
   
   // consts
   
   #define REDIRECT_PREFIX "REDIRECT_"
   #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 
   
 const char *argv0;  static const char* argv0;
 Pool_storage pool_storage;  static const char* config_filespec_cstr=0;
 Pool pool(&pool_storage); // global pool [dont describe to doxygen: it confuses it with param names]  static bool fail_on_config_read_problem=true;
 bool cgi; ///< we were started as CGI?  
   static int args_skip=1;
   static char** argv_all = NULL;
   
   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]
   
   // for signal handlers
   Request *request=0;
   Request_info *request_info=0;
   bool execution_canceled=false;
   
 // SAPI  // SAPI
   
 static void log(const char *fmt, va_list args) {  class SAPI_Info{} SAPI_info;
         bool opened;  
   static void log(const char* fmt, va_list args) {
           bool opened=false;
         FILE *f=0;          FILE *f=0;
   
         if(argv0) {          const char* log_by_env=getenv(PARSER_LOG_ENV_NAME);
                 // beside by binary          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];
                   strncpy(beside_config_path, config_filespec_cstr, MAX_STRING-1);  beside_config_path[MAX_STRING-1]=0;
                   if(!(
                           rsplit(beside_config_path, '/') || 
                           rsplit(beside_config_path, '\\'))) { // strip filename
                           // no path, just filename
                           beside_config_path[0]='.'; beside_config_path[1]=0;
                   }
   
                 char file_spec[MAX_STRING];                  char file_spec[MAX_STRING];
                 strncpy(file_spec, argv0, MAX_STRING-1);  file_spec[MAX_STRING-1]=0; // filespec of my binary                  snprintf(file_spec, MAX_STRING, 
                 rsplit(file_spec, '/');  rsplit(file_spec, '\\');// strip filename                          "%s/parser3.log", beside_config_path);
                 strcat(file_spec, "/parser3.log");  
                 f=fopen(file_spec, "at");                  f=fopen(file_spec, "at");
                   opened=f!=0;
         }          }
         opened=f!=0;          // fallback to stderr
         if(!opened)          if(!opened)
                 f=stderr;                  f=stderr;
   
           // use no memory [so that we could log out-of-memory error]
           setbuf(f, 0); // stderr stream is unbuffered by default, but still...
   
         // prefix          // prefix
         time_t t=time(0);          time_t t=time(0);
         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] [%u] ", 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=%u]",
                           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
 // appends to parser3.log located beside my binary if openable, to stderr otherwize  static void log(const char* fmt, ...) {
 void SAPI::log(Pool& , 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);
 }  }
   #endif
   
 void SAPI::die(const char *fmt, ...) {  // 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_list args;
         va_start(args,fmt);          va_start(args,fmt);
         ::log(fmt, args);          ::log(fmt, args);
         va_end(args);          va_end(args);
   }
   
         char body[MAX_STRING];  static void die_or_abort(const char* fmt, va_list args, bool write_core) {
         size_t size=vsnprintf(body, MAX_STRING, fmt, args);          // log
   
         //          // logging is more important than user 
         int content_length=strlen(body);          // she can cancel download, we'd get SIGPIPE, 
           // nothing would be logged then
           ::log(fmt, args);
   
           // inform user
   
           char body[MAX_STRING];
           int content_length=vsnprintf(body, MAX_STRING, fmt, args);
   
         // prepare header          // prepare header
         // let's be honest, that's bad we couldn't produce valid output          // let's be honest, that's bad we couldn't produce valid output
         SAPI::add_header_attribute(pool, "status", "500");          SAPI::add_header_attribute(SAPI_info, HTTP_STATUS, "500");
         SAPI::add_header_attribute(pool, "content-type", "text/plain");          SAPI::add_header_attribute(SAPI_info, HTTP_CONTENT_TYPE, "text/plain");
         char content_length_cstr[MAX_NUMBER];          SAPI::add_header_attribute(SAPI_info, HTTP_CONTENT_LENGTH, format(content_length, "%u"));
         snprintf(content_length_cstr, MAX_NUMBER, "%u", content_length);  
         SAPI::add_header_attribute(pool, "content-length", content_length_cstr);  
   
         // send header          // send header
         SAPI::send_header(pool);          SAPI::send_header(SAPI_info);
   
         // body          // body
         SAPI::send_body(pool, body, content_length);          SAPI::send_body(SAPI_info, body, content_length);
   
         exit(1);          // exit & try to produce core dump[unix] or invoke debugger[Win32 Debug version]
           if(write_core) {
   #if defined(WIN32) && !defined(_DEBUG)
                   // IIS with abort failes to show STDOUT, it just barks "abnormal program termination"
                   exit(1);
   #else
   #if _MSC_VER
                   _asm int 3;
   #endif
                   abort();
   #endif
           } 
           else
                   exit(1);
 }  }
   
 const char *SAPI::get_env(Pool& , const char *name) {  void SAPI::die(const char* fmt, ...) {
         return getenv(name);      va_list args;
           va_start(args, fmt);
           die_or_abort(fmt, args, false/*write core?*/);
   //unreachable anyway    va_end(args);
   }
   
   void SAPI::abort(const char* fmt, ...) {
       va_list args;
           va_start(args, fmt);
           die_or_abort(fmt, args, true/*write core?*/);
   //unreachable anyway    va_end(args);
   }
   
   char* SAPI::get_env(SAPI_Info& , const char* name) {
           if(char *local=getenv(name))
                   return pa_strdup(local);
           else
                   return 0;
   }
   
   const char* const *SAPI::environment(SAPI_Info&) {
   #ifdef _MSC_VER
           extern char **_environ;
           return _environ;
   #else
           extern char **environ;
           return environ;
   #endif
 }  }
   
 size_t SAPI::read_post(Pool& , char *buf, size_t max_bytes) {  size_t SAPI::read_post(SAPI_Info& , char *buf, size_t max_bytes) {
         size_t read_size=0;          size_t read_size=0;
         do {          do {
                 int chunk_size=read(fileno(stdin),                   ssize_t chunk_size=read(fileno(stdin), 
                         buf+read_size, min(READ_POST_CHUNK_SIZE, max_bytes-read_size));                          buf+read_size, min(READ_POST_CHUNK_SIZE, max_bytes-read_size));
                 if(chunk_size<=0)                  if(chunk_size<=0)
                         break;                          break;
Line 156  size_t SAPI::read_post(Pool& , char *buf Line 235  size_t SAPI::read_post(Pool& , char *buf
         return read_size;          return read_size;
 }  }
   
 void SAPI::add_header_attribute(Pool& , const char *key, const char *value) {  void SAPI::add_header_attribute(SAPI_Info& , const char* dont_store_key, const char* dont_store_value) {
         if(cgi)          if( cgi && (!request || !request->console.was_used()) )
                 printf("%s: %s\n", key, value);                  printf("%s: %s\n", dont_store_key, dont_store_value);
 }  }
   
 /// @todo intelligent cache-control  /// @todo intelligent cache-control
 void SAPI::send_header(Pool& ) {  void SAPI::send_header(SAPI_Info& ) {
         if(cgi) {          if(cgi) {
                 puts("expires: Fri, 23 Mar 2001 09:32:23 GMT");  //              puts("expires: Fri, 23 Mar 2001 09:32:23 GMT");
   
                 // header | body  delimiter                  // header | body  delimiter
                 puts("");                  puts("");
         }          }
 }  }
   
 void SAPI::send_body(Pool& , 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);
 }  }
   
 //  //
   
 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
                           )
                                   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
   }
   
   static void log_signal(const char* signal_name) {
           if(request_info)
                   SAPI::log(SAPI_info, "%s received while %s. uri=%s, method=%s, cl=%u",
                           signal_name,
                           request?"executing code":"reading data",
                           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
   static void SIGUSR1_handler(int /*sig*/){
           log_signal("SIGUSR1");
   }
   #endif
   
   #ifdef SIGPIPE
   #define SIGPIPE_NAME "SIGPIPE"
   static const String sigpipe_name(SIGPIPE_NAME);
   static void SIGPIPE_handler(int /*sig*/){
           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;
           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 file_name;          
           return original;
 }  }
   #endif
   
 /**  /**
 main workhorse  main workhorse
Line 195  main workhorse Line 361  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.
 */  */
 void real_parser_handler(  static void real_parser_handler(const char* filespec_to_process,
                                         const char *filespec_to_process,                                  const char* request_method, bool header_only) 
                                         const char *request_method, bool header_only) {  {
         // init socks          // init socks
         init_socks(pool);          pa_socks_init();
           
 #ifdef XML  
         /**  
         * Initialize Xerces and Xalan.  
         *  
         * Should be called only once per process before making  
         * any other API calls.  
         */  
         //_asm int 3;  
         XalanInitialize();  
 #endif  
           
         // init global classes  
         init_methoded_array(pool);  
         // init global variables          // init global variables
         pa_globals_init(pool);          pa_globals_init();
                   
         if(!filespec_to_process)          if(!filespec_to_process || !*filespec_to_process)
                 throw Exception(0, 0,                  SAPI::die("Parser/%s"
                 0,  #ifdef PA_DEBUG_CGI_ENTRY_EXIT
                 "Parser/%s", PARSER_VERSION);                  " 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];
         if(cgi) {          if(cgi) {
                 if(const char *env_document_root=SAPI::get_env(pool, "DOCUMENT_ROOT"))                  if(const char* env_document_root=getenv("DOCUMENT_ROOT"))
                         request_info.document_root=env_document_root;                          request_info.document_root=env_document_root;
                 else if(const char *path_info=SAPI::get_env(pool, "PATH_INFO")) {                  else if(const char* path_info=getenv("PATH_INFO")) {
                         // IIS                          // IIS
                         size_t len=strlen(filespec_to_process)-strlen(path_info);                          size_t len=min(sizeof(document_root_buf)-1, strlen(filespec_to_process)-strlen(path_info));
                         char *buf=(char *)pool.malloc(len+1);                          memcpy(document_root_buf, filespec_to_process, len); document_root_buf[len]=0;
                         memcpy(buf, filespec_to_process, len); buf[len]=0;                          request_info.document_root=document_root_buf;
                         request_info.document_root=buf;  
                 } else                  } else
                         throw Exception(0, 0,                          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 {
                 static char buf[MAX_STRING];                  full_file_spec("", document_root_buf, sizeof(document_root_buf));
                 strncpy(buf, filespec_to_process, MAX_STRING-1); buf[MAX_STRING-1]=0;                  request_info.document_root=document_root_buf;
                 if(rsplit(buf, '/') || rsplit(buf, '\\')) // strip filename  
                         request_info.document_root=buf;  
                 else  
                         request_info.document_root="";  
         }          }
         request_info.path_translated=filespec_to_process;          request_info.path_translated=filespec_to_process;
         request_info.method=request_method ? request_method : "GET";          request_info.method=request_method ? request_method : "GET";
         const char *query_string=SAPI::get_env(pool, "QUERY_STRING");          const char* query_string=
   #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) {
                 if(const char *env_request_uri=SAPI::get_env(pool, "REQUEST_URI"))                  // few absolute obligatory
                   const char* path_info=getenv("PATH_INFO");
                   if(!path_info)
                           SAPI::die("CGI: illegal call (missing PATH_INFO)");
                   const char* script_name=getenv("SCRIPT_NAME");
                   if(!script_name)
                                   SAPI::die("CGI: illegal call (missing SCRIPT_NAME)");
   
                   const char* env_request_uri=getenv("REQUEST_URI");
                   if(env_request_uri)
                         request_info.uri=env_request_uri;                          request_info.uri=env_request_uri;
                 else if(const char *path_info=SAPI::get_env(pool, "PATH_INFO"))                  else 
                         if(query_string) {                          if(query_string) {
                                 char *reconstructed_uri=(char *)pool.malloc(                                  char* reconstructed_uri=new(PointerFreeGC) char[
                                         strlen(path_info)+1/*'?'*/+                                          strlen(path_info)+1/*'?'*/+
                                         strlen(query_string)+1/*0*/);                                          strlen(query_string)+1/*0*/];
                                 strcpy(reconstructed_uri, path_info);                                  strcpy(reconstructed_uri, path_info);
                                 strcat(reconstructed_uri, "?");                                  strcat(reconstructed_uri, "?");
                                 strcat(reconstructed_uri, query_string);                                  strcat(reconstructed_uri, query_string);
                                 request_info.uri=reconstructed_uri;                                  request_info.uri=reconstructed_uri;
                         } else                          } else
                                 request_info.uri=path_info;                                  request_info.uri=path_info;
                         else  
                                 throw Exception(0, 0,                  if(env_request_uri) { // apache & others stuck to standards
                                 0,                          /*
                                 "CGI: no PATH_INFO defined(in reinventing REQUEST_URI)");                                  http://parser3/env.html?123  =OK
                                                           $request:uri=/env.html?123
                         if(const char *script_name=SAPI::get_env(pool, "SCRIPT_NAME")) {                                  REQUEST_URI='/env.html?123'
                                 size_t script_name_len=strlen(script_name);                                  SCRIPT_NAME='/cgi-bin/parser3'
                                 size_t uri_len=strlen(request_info.uri);                                  PATH_INFO='/env.html'
                                 if(strncmp(request_info.uri,script_name, script_name_len)==0 &&  
                                         script_name_len != uri_len) // under IIS they are the same                                  http://parser3/cgi-bin/parser3/env.html?123 =ERROR
                                         throw Exception(0, 0,                                  $request:uri=/cgi-bin/parser3/env.html?123
                                         0,                                  REQUEST_URI='/cgi-bin/parser3/env.html?123'
                                         "CGI: illegal call");                                  SCRIPT_NAME='/cgi-bin/parser3'
                         }                                  PATH_INFO='/env.html'
                           */
                           size_t script_name_len=strlen(script_name);
                           size_t uri_len=strlen(env_request_uri);
                           if(strncmp(env_request_uri, script_name, script_name_len)==0 &&
                                   script_name_len != uri_len) // under IIS they are the same
                                   SAPI::die("CGI: illegal call (1)");
                   } else { // seen on IIS5
                           /*
                                   http://nestle/env.html?123 =OK
                                   $request:uri=/env.html?123
                                   REQUEST_URI=''
                                   SCRIPT_NAME='/env.html'
                                   PATH_INFO='/env.html'
   
                                   http://nestle/cgi-bin/parser3.exe/env.html =ERROR
                                   $request:uri=/env.html
                                   REQUEST_URI=''
                                   SCRIPT_NAME='/cgi-bin/parser3.exe'
                                   PATH_INFO='/env.html'
                           */
                           if(strcmp(script_name, path_info)!=0)
                                   SAPI::die("CGI: illegal call (2)");
                   }
         } else          } else
                 request_info.uri=0;                  request_info.uri="";
                   
         request_info.content_type=SAPI::get_env(pool, "CONTENT_TYPE");          request_info.content_type=getenv("CONTENT_TYPE");
         const char *content_length=SAPI::get_env(pool, "CONTENT_LENGTH");          const char* content_length=getenv("CONTENT_LENGTH");
         request_info.content_length=(content_length?atoi(content_length):0);          request_info.content_length=(content_length?atoi(content_length):0);
         request_info.cookie=SAPI::get_env(pool, "HTTP_COOKIE");          request_info.cookie=getenv("HTTP_COOKIE");
         request_info.user_agent=SAPI::get_env(pool, "HTTP_USER_AGENT");          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(pool,          Request request(SAPI_info, request_info,
                 request_info,                  cgi ? String::Language(String::L_HTML|String::L_OPTIMIZE_BIT) : String::L_AS_IS,
                 cgi ? String::UL_USER_HTML : String::UL_AS_IS,  
                 true /* status_allowed */);                  true /* status_allowed */);
           
         // some root-controlled location          // get request ptr for signal handlers
 #ifdef SYSCONFDIR          ::request=&request;
         const char *root_config_filespec=SYSCONFDIR "/" CONFIG_FILE_NAME;  
 #else          char config_filespec_buf[MAX_STRING];
 #       ifdef WIN32          if(!config_filespec_cstr) {
         // c:\windows                  const char* config_by_env=getenv(PARSER_CONFIG_ENV_NAME);
         char root_config_path[MAX_STRING];                  if(!config_by_env)
         GetWindowsDirectory(root_config_path, MAX_STRING);                          config_by_env=getenv(REDIRECT_PREFIX PARSER_CONFIG_ENV_NAME);
                           if(config_by_env)
         char root_config_filespec[MAX_STRING];                          config_filespec_cstr=config_by_env;
         snprintf(root_config_filespec, MAX_STRING,                   else {
                 "%s/%s",                           // beside by binary
                 root_config_path, CONFIG_FILE_NAME);                          char beside_binary_path[MAX_STRING];
 #       else                          strncpy(beside_binary_path, argv0, MAX_STRING-1);  beside_binary_path[MAX_STRING-1]=0; // filespec of my binary
 #error must be compiled either configure/make or MSVC++                          if(!(
 #       endif                                  rsplit(beside_binary_path, '/') || 
 #endif                                  rsplit(beside_binary_path, '\\'))) { // strip filename
                                           // no path, just filename
         // beside by binary                                  // @todo full path, not ./!
         // @todo full path, not ./!                                  beside_binary_path[0]='.'; beside_binary_path[1]=0;
         static char site_config_path[MAX_STRING];                          }
         strncpy(site_config_path, argv0, MAX_STRING-1);  site_config_path[MAX_STRING-1]=0; // filespec of my binary                          snprintf(config_filespec_buf, MAX_STRING, 
         if(!(                                  "%s/%s", 
                 rsplit(site_config_path, '/') ||                                   beside_binary_path, AUTO_FILE_NAME);
                 rsplit(site_config_path, '\\'))) { // strip filename                          config_filespec_cstr=config_filespec_buf;
                 // no path, just filename                          fail_on_config_read_problem=entry_exists(config_filespec_cstr);
                 site_config_path[0]='.'; site_config_path[1]=0;                  }
         }          }
                   
         char site_config_filespec[MAX_STRING];  
         snprintf(site_config_filespec, MAX_STRING,   
                 "%s/%s",   
                 site_config_path, CONFIG_FILE_NAME);  
           
         // process the request          // process the request
         request.core(          request.core(
                 root_config_filespec, false,                  config_filespec_cstr, fail_on_config_read_problem,
                 site_config_filespec, false,  
                 header_only);                  header_only);
           
           // no request [prevent signal handlers from accessing invalid memory]
           ::request=0;
   
           // finalize global variables
           pa_globals_done();
   
         //          //
         done_socks();          pa_socks_done();
           
 #ifdef DEBUG_POOL_MALLOC  
         extern void log_pool_stats(Pool& pool);  
         log_pool_stats(pool);  
 #endif  
 }  }
   
 void call_real_parser_handler__do_SEH(  #ifdef PA_SUPPRESS_SYSTEM_EXCEPTION
                                                                  const char *filespec_to_process,  static const Exception 
                                                                  const char *request_method, bool header_only) {  call_real_parser_handler__do_PEH_return_it(
 #if _MSC_VER && !defined(_DEBUG)          const char* filespec_to_process,
           const char* request_method, bool header_only) 
   {
           try {
                   real_parser_handler(
                           filespec_to_process,
                           request_method, header_only);
           } catch(const Exception& e) {
                   return e;
           }
   
           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;          LPEXCEPTION_POINTERS system_exception=0;
   
         __try {          __try {
 #endif                  parser_exception=call_real_parser_handler__do_PEH_return_it(
                 real_parser_handler(  
                         filespec_to_process,                          filespec_to_process,
                         request_method, header_only);                          request_method, header_only);
                   
 #if _MSC_VER && !defined(_DEBUG)  
         } __except (          } __except (
                 (system_exception=GetExceptionInformation()),                   (system_exception=GetExceptionInformation()), 
                 EXCEPTION_EXECUTE_HANDLER) {                  EXCEPTION_EXECUTE_HANDLER) 
                           {
   
                 if(system_exception)                  if(system_exception)
                         if(_EXCEPTION_RECORD *er=system_exception->ExceptionRecord)                          if(_EXCEPTION_RECORD *er=system_exception->ExceptionRecord)
                                 throw Exception(0, 0,                                  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  
                                 throw Exception(0, 0, 0, "Exception <no exception record>");  
                         else                          else
                                 throw Exception(0, 0, 0, "Exception <no exception information>");                                  throw Exception("system", 
                                           0, 
                                           "<no exception record>");
                   else
                           throw Exception("system", 
                                   0, 
                                   "<no exception information>");
         }          }
 #endif  
 }  
   
 #ifdef WIN32          if(parser_exception)
 int failed_new(size_t size) {                  throw Exception(parser_exception);
         SAPI::die("out of memory in 'new', failed to allocated %u bytes", size);  
         return 0; // not reached  
 }  }
 #endif  #endif
   
 #ifdef HAVE_SET_NEW_HANDLER  static void usage(const char* program) {
 void failed_new() {          printf(
     SAPI::die("out of memory in 'new'");                  "Parser/%s\n"
                   "Copyright(c) 2001-2009 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
                   "    -f config_file  Use this config file (/path/to/auto.p)\n"
                   "    -h              Display usage information (this message)\n"
                   , PARSER_VERSION, 
                   program);
           exit(EINVAL);
 }  }
 #endif  
   
 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;
   
   #ifndef PA_DEBUG_DISABLE_GC
           // Dont collect unless explicitly requested 
           // this is quicker (~30% ), but less memory-efficient(~8%)
           // so deciding for speed
           GC_dont_gc=1; 
   #endif
   /*
           
           Array<int> test;
           test+=3;
           test+=4;
   //      int a=test.count();
           int i=0;
           scanf("%d", &i);
           int b=test.get(i);
   //      int b=test.get(10);
           printf("%d", b);//test.count());*/
   
   #ifdef SIGUSR1
       if(signal(SIGUSR1, SIGUSR1_handler)==SIG_ERR)
                   SAPI::die("Can not set handler for SIGUSR1");
   #endif
   #ifdef SIGPIPE
       if(signal(SIGPIPE, SIGPIPE_handler)==SIG_ERR)
                   SAPI::die("Can not set handler for SIGPIPE");
   #endif
   
   
   #ifdef DEBUG_MAILRECEIVE
           if(FILE *fake_in=fopen(DEBUG_MAILRECEIVE, "rt")) {
                   dup2(fake_in->_file, 0/*STDIN_FILENO*/);
           }
   #endif
   
   #ifdef _DEBUG
           //_crtBreakAlloc=46;
   #endif
           argv_all=argv;
         argv0=argv[0];          argv0=argv[0];
   
         umask(2);          umask(2);
Line 395  int main(int argc, char *argv[]) { Line 667  int main(int argc, char *argv[]) {
                 getenv("GATEWAY_INTERFACE") ||                   getenv("GATEWAY_INTERFACE") || 
                 getenv("REQUEST_METHOD");                  getenv("REQUEST_METHOD");
                   
         if(!cgi) {          char *raw_filespec_to_process;
                 if(argc<2) {          if(cgi) {
                         printf(                  raw_filespec_to_process=getenv("PATH_TRANSLATED");
                                 "Parser/%s Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com)\n"                  if(raw_filespec_to_process && !*raw_filespec_to_process)
                                 "Author: Alexander Petrosyan <paf@design.ru>(http://paf.design.ru)\n"                          raw_filespec_to_process=0;
                                 "\n"          } else {
                                 "Usage: %s <file>\n",                  int optind=1;
                                 PARSER_VERSION,                   while(optind < argc){
                                 argv0?argv0:"parser3");                          char *carg = argv[optind];
                         return 1;                          if(carg[0] != '-')
                                   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
                                           case 'm':
                                                   mail_received=true;
                                                   break;
   #endif
                                           default:
                                                   fprintf(stderr, "%s: invalid option '%c'\n", argv[0], c);
                                                   usage(argv[0]);
                                                   break;
                                   }
                           }
                           optind++;
                 }                  }
                   
                   if (optind > argc - 1) {
                           fprintf(stderr, "%s: file not specified\n", argv[0]);
                           usage(argv[0]);
                   }
                   raw_filespec_to_process=argv[optind];
                   args_skip=optind;
         }          }
   
 #ifdef WIN32  #ifdef WIN32
Line 414  int main(int argc, char *argv[]) { Line 719  int main(int argc, char *argv[]) {
         setmode(fileno(stderr), _O_BINARY);          setmode(fileno(stderr), _O_BINARY);
 #endif  #endif
   
         char *filespec_to_process=cgi?getenv("PATH_TRANSLATED"):argv[1];  #if defined(_MSC_VER) && defined(_DEBUG)
 #ifdef WIN32          // Get current flag
         back_slashes_to_slashes(filespec_to_process);          int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
 #endif  
         filespec_to_process=full_file_spec(filespec_to_process);  
   
         const char *request_method=getenv("REQUEST_METHOD");          // Turn on leak-checking bit
         bool header_only=request_method && strcasecmp(request_method, "HEAD")==0;          tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
   
 #ifdef WIN32          // Set flag to the new value
         _set_new_handler(failed_new);          _CrtSetDbgFlag( tmpFlag );
 #endif  //      _CrtSetBreakAlloc(61);
   
 #ifdef HAVE_SET_NEW_HANDLER          _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
         std::set_new_handler(failed_new);          _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
 #endif  #endif
   
           char filespec_to_process[MAX_STRING];
           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          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
                   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
                   SAPI::add_header_attribute(SAPI_info, HTTP_CONTENT_TYPE, "text/plain");
                   SAPI::add_header_attribute(SAPI_info, HTTP_CONTENT_LENGTH, format(content_length, "%u"));
   
                   // 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: ", e.comment());                  // unsuccessful finish
 #ifndef _DEBUG  
         } catch(...) {   
                 SAPI::die("<unknown exception>");  
 #endif  
         }          }
           
   
 #ifndef WIN32  #ifdef PA_DEBUG_CGI_ENTRY_EXIT
         //           log("main: successful return");
         if(!cgi)  
                 SAPI::send_body(pool, "\n", 1);  
 #endif  #endif
         return 0;          return 0;
 }  }

Removed from v.1.135  
changed lines
  Added in v.1.253


E-mail: