Annotation of parser3/src/targets/cgi/parser3.C, revision 1.309
1.27 paf 1: /** @file
2: Parser: scripting and CGI main.
3:
1.277 moko 4: Copyright (c) 2001-2017 Art. Lebedev Studio (http://www.artlebedev.com)
1.154 paf 5: Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
1.189 paf 6: */
1.27 paf 7:
1.309 ! moko 8: volatile const char * IDENT_PARSER3_C="$Id: parser3.C,v 1.308 2020/11/12 15:06:12 moko Exp $";
1.1 paf 9:
1.40 paf 10: #include "pa_config_includes.h"
1.3 paf 11:
1.37 paf 12: #include "pa_sapi.h"
1.76 paf 13: #include "classes.h"
1.24 paf 14: #include "pa_common.h"
1.2 paf 15: #include "pa_request.h"
1.68 paf 16: #include "pa_version.h"
1.266 moko 17: #include "pa_vconsole.h"
1.294 moko 18: #include "pa_sapi_info.h"
1.207 paf 19:
1.263 moko 20: #ifdef _MSC_VER
1.264 moko 21: #include <crtdbg.h>
1.263 moko 22: #include <windows.h>
23: #include <direct.h>
1.120 parser 24: #endif
25:
1.232 paf 26: // defines
1.231 paf 27:
1.233 paf 28: // comment remove me after debugging
1.288 moko 29: //#define PA_DEBUG_CGI_ENTRY_EXIT "parser3-debug.log"
1.233 paf 30:
1.278 moko 31: #if defined(_MSC_VER) && !defined(_DEBUG)
1.231 paf 32: # define PA_SUPPRESS_SYSTEM_EXCEPTION
33: #endif
34:
1.109 parser 35: // consts
1.84 parser 36:
1.175 paf 37: #define REDIRECT_PREFIX "REDIRECT_"
1.181 paf 38: #define PARSER_CONFIG_ENV_NAME "CGI_PARSER_CONFIG"
1.226 paf 39: #define PARSER_LOG_ENV_NAME "CGI_PARSER_LOG"
1.159 paf 40:
1.308 moko 41: static const char* filespec_to_process=0; // [file]
1.293 moko 42: static const char* config_filespec_cstr=0; // -f option
1.296 moko 43: static const char* httpd_host_port=0; // -p option
1.293 moko 44: static bool mail_received=false; // -m option? [asked to parse incoming message to $mail:received]
1.192 paf 45:
1.245 misha 46: static int args_skip=1;
47: static char** argv_all = NULL;
48:
1.184 paf 49: static bool cgi; ///< we were started as CGI?
1.5 paf 50:
1.201 paf 51: // for signal handlers
52: Request *request=0;
1.309 ! moko 53:
1.297 moko 54: // for die error logging
1.309 ! moko 55: static Request_info request_info;
1.201 paf 56:
1.46 paf 57: // SAPI
1.86 parser 58:
1.218 paf 59: static void log(const char* fmt, va_list args) {
1.193 paf 60: bool opened=false;
1.61 paf 61: FILE *f=0;
62:
1.226 paf 63: const char* log_by_env=getenv(PARSER_LOG_ENV_NAME);
64: if(!log_by_env)
65: log_by_env=getenv(REDIRECT_PREFIX PARSER_LOG_ENV_NAME);
66: if(log_by_env) {
67: f=fopen(log_by_env, "at");
68: opened=f!=0;
69: }
1.272 moko 70: #ifdef PA_DEBUG_CGI_ENTRY_EXIT
1.233 paf 71: f=fopen(PA_DEBUG_CGI_ENTRY_EXIT, "at");
72: opened=f!=0;
73: #endif
1.226 paf 74:
75: if(!opened && config_filespec_cstr) {
1.193 paf 76: char beside_config_path[MAX_STRING];
77: strncpy(beside_config_path, config_filespec_cstr, MAX_STRING-1); beside_config_path[MAX_STRING-1]=0;
1.272 moko 78: if(!(rsplit(beside_config_path, '/') || rsplit(beside_config_path, '\\'))) { // strip filename
1.193 paf 79: // no path, just filename
80: beside_config_path[0]='.'; beside_config_path[1]=0;
81: }
82:
83: char file_spec[MAX_STRING];
1.272 moko 84: snprintf(file_spec, MAX_STRING, "%s/parser3.log", beside_config_path);
1.193 paf 85: f=fopen(file_spec, "at");
86: opened=f!=0;
87: }
1.192 paf 88: // fallback to stderr
1.61 paf 89: if(!opened)
90: f=stderr;
1.208 paf 91:
92: // use no memory [so that we could log out-of-memory error]
93: setbuf(f, 0); // stderr stream is unbuffered by default, but still...
1.61 paf 94:
95: // prefix
96: time_t t=time(0);
1.218 paf 97: if(const char* stamp=ctime(&t)) { // never saw that
1.173 paf 98: if(size_t len=strlen(stamp)) // saw once stamp being =""
1.272 moko 99: fprintf(f, "[%.*s] [%u] ", (int)len-1, stamp, (unsigned int)getpid() );
1.171 paf 100: }
1.61 paf 101: // message
1.117 parser 102:
1.246 misha 103: char buf[MAX_LOG_STRING];
104: size_t size=vsnprintf(buf, MAX_LOG_STRING, fmt, args);
105: size=remove_crlf(buf, buf+size);
1.239 paf 106: fwrite(buf, size, 1, f);
107:
1.297 moko 108: if(request_info.method) {
1.302 moko 109: fprintf(f, " [uri=%s, method=%s, cl=%lu]\n", request_info.uri ? request_info.uri : "<unknown>", request_info.method, (unsigned long)request_info.content_length);
1.297 moko 110: } else
111: fputs(" [no request info]\n", f);
1.61 paf 112:
113: if(opened)
114: fclose(f);
1.85 parser 115: else
116: fflush(f);
1.124 parser 117: }
1.272 moko 118:
1.236 paf 119: #ifdef PA_DEBUG_CGI_ENTRY_EXIT
1.233 paf 120: static void log(const char* fmt, ...) {
1.272 moko 121: va_list args;
1.233 paf 122: va_start(args,fmt);
123: log(fmt, args);
124: va_end(args);
125: }
1.236 paf 126: #endif
1.124 parser 127:
128: // appends to parser3.log located beside my binary if openable, to stderr otherwize
1.218 paf 129: void SAPI::log(SAPI_Info&, const char* fmt, ...) {
1.272 moko 130: va_list args;
1.124 parser 131: va_start(args,fmt);
132: ::log(fmt, args);
133: va_end(args);
134: }
135:
1.290 moko 136: void SAPI::die(const char* fmt, ...) {
137: va_list args;
138:
139: // logging first, first vsnprintf
140: va_start(args,fmt);
141: ::log(fmt, args);
142: va_end(args);
1.138 paf 143:
1.290 moko 144: // inform user, second vsnprintf
145: va_start(args, fmt);
1.299 moko 146: char message[MAX_STRING];
1.300 moko 147: vsnprintf(message, MAX_STRING, fmt, args);
1.134 paf 148:
1.299 moko 149: SAPI::send_error(*sapiInfo, message);
1.290 moko 150: exit(1);
1.258 moko 151: // va_end(args);
1.28 paf 152: }
153:
1.294 moko 154: char* SAPI::Env::get(SAPI_Info& info, const char* name) {
155: return info.get_env(name);
1.218 paf 156: }
157:
1.305 moko 158: bool SAPI::Env::set(SAPI_Info& info, const char* name, const char* value) {
159: return info.set_env(name, value);
160: }
161:
1.294 moko 162: const char* const *SAPI::Env::get(SAPI_Info& info) {
163: return info.get_env();
1.180 paf 164: }
165:
1.294 moko 166: size_t SAPI::read_post(SAPI_Info& info, char *buf, size_t max_bytes) {
167: return info.read_post(buf, max_bytes);
1.10 paf 168: }
169:
1.294 moko 170: void SAPI::add_header_attribute(SAPI_Info& info, const char* dont_store_key, const char* dont_store_value) {
171: info.add_header_attribute(dont_store_key, dont_store_value);
1.19 paf 172: }
173:
1.294 moko 174: void SAPI::send_header(SAPI_Info& info) {
175: info.send_header();
1.30 paf 176: }
1.20 paf 177:
1.294 moko 178: size_t SAPI::send_body(SAPI_Info& info, const void *buf, size_t size) {
179: return info.send_body(buf, size);
1.58 paf 180: }
181:
1.218 paf 182: static void full_file_spec(const char* file_name, char *buf, size_t buf_size) {
1.308 moko 183: if(file_name[0]=='/'
1.167 paf 184: #ifdef WIN32
1.308 moko 185: || file_name[0] && file_name[1]==':'
1.167 paf 186: #endif
1.308 moko 187: ){
188: strncpy(buf, file_name, buf_size-1); buf[buf_size-1]=0;
189: } else {
190: char cwd[MAX_STRING];
191: snprintf(buf, buf_size, "%s/%s", getcwd(cwd, MAX_STRING) ? cwd : "", file_name);
192: }
1.166 paf 193: #ifdef WIN32
194: back_slashes_to_slashes(buf);
195: #endif
1.97 parser 196: }
197:
1.218 paf 198: static void log_signal(const char* signal_name) {
1.294 moko 199: SAPI::log(*sapiInfo, "%s received %s processing request", signal_name, request ? "while" : "before or after");
1.205 paf 200: }
201:
1.201 paf 202: #ifdef SIGUSR1
1.205 paf 203: static void SIGUSR1_handler(int /*sig*/){
204: log_signal("SIGUSR1");
1.201 paf 205: }
206: #endif
207:
208: #ifdef SIGPIPE
1.243 misha 209: #define SIGPIPE_NAME "SIGPIPE"
210: static const String sigpipe_name(SIGPIPE_NAME);
1.205 paf 211: static void SIGPIPE_handler(int /*sig*/){
1.243 misha 212: Value* sigpipe=0;
213: if(request)
1.251 misha 214: sigpipe=request->main_class.get_element(sigpipe_name);
1.243 misha 215: if(sigpipe && sigpipe->as_bool())
1.244 misha 216: log_signal(SIGPIPE_NAME);
1.243 misha 217:
1.201 paf 218: if(request)
1.276 moko 219: request->set_skip(Request::SKIP_INTERRUPTED);
1.201 paf 220: }
221: #endif
222:
1.227 paf 223: #ifdef WIN32
1.292 moko 224: const char* maybe_reconstruct_IIS_status_in_qs(const char* original) {
1.228 paf 225: // 404;http://servername/page[?param=value...]
1.227 paf 226: // ';' should be urlencoded by HTTP standard, so we shouldn't get it from browser
227: // and can consider that as an indication that this is IIS way to report errors
228:
1.272 moko 229: if(original && isdigit((unsigned char)original[0]) && isdigit((unsigned char)original[1]) && isdigit((unsigned char)original[2]) && original[3]==';'){
1.227 paf 230: size_t original_len=strlen(original);
1.272 moko 231: char* reconstructed=new(PointerFreeGC) char[original_len +12/*IIS-STATUS=&*/ +14/*IIS-DOCUMENT=&*/ +1];
1.227 paf 232: char* cur=reconstructed;
233: memcpy(cur, "IIS-STATUS=", 11); cur+=11;
234: memcpy(cur, original, 3); cur+=3;
235: *cur++='&';
236:
1.228 paf 237: const char* qmark_at=strchr(original, '?');
1.227 paf 238: memcpy(cur, "IIS-DOCUMENT=", 13); cur+=13;
239: {
1.272 moko 240: size_t value_len=(qmark_at ? qmark_at-original : original_len)-4;
1.227 paf 241: memcpy(cur, original+4, value_len); cur+=value_len;
242: }
243:
244: if(qmark_at) {
245: *cur++='&';
246: strcpy(cur, qmark_at+1/*skip ? itself*/);
247: } else
248: *cur=0;
249:
250: return reconstructed;
251: }
252:
253: return original;
254: }
1.283 moko 255:
256: #define MAYBE_RECONSTRUCT_IIS_STATUS_IN_QS(s) maybe_reconstruct_IIS_status_in_qs(s)
257: #else
258: #define MAYBE_RECONSTRUCT_IIS_STATUS_IN_QS(s) s
1.227 paf 259: #endif
260:
1.256 misha 261:
262: class RequestController {
263: public:
264: RequestController(Request* r){
265: ::request=r;
266: }
267: ~RequestController(){
268: ::request=0;
269: }
270: };
271:
1.288 moko 272: static bool locate_config(){
273: if(!config_filespec_cstr) {
274: config_filespec_cstr=getenv(PARSER_CONFIG_ENV_NAME);
275: if(!config_filespec_cstr)
276: config_filespec_cstr=getenv(REDIRECT_PREFIX PARSER_CONFIG_ENV_NAME);
277: if(!config_filespec_cstr){
278: // beside by binary
279: char beside_binary_path[MAX_STRING];
280: strncpy(beside_binary_path, argv_all[0], MAX_STRING-1); beside_binary_path[MAX_STRING-1]=0; // filespec of my binary
281: if(!(rsplit(beside_binary_path, '/') || rsplit(beside_binary_path, '\\'))) { // strip filename
282: // no path, just filename
283: // @todo full path, not ./!
284: beside_binary_path[0]='.'; beside_binary_path[1]=0;
285: }
286: char config_filespec_buf[MAX_STRING];
287: snprintf(config_filespec_buf, MAX_STRING, "%s/%s", beside_binary_path, AUTO_FILE_NAME);
288: config_filespec_cstr=pa_strdup(config_filespec_buf);
289: return entry_exists(config_filespec_cstr);
290: }
291: }
292: return true;
293: }
1.256 misha 294:
1.308 moko 295: static void connection_handler(SAPI_Info_HTTPD &info, HTTPD_Connection &connection){
1.294 moko 296: connection.read_header();
1.295 moko 297: info.populate_env();
1.294 moko 298:
1.299 moko 299: // connection request info, still global for correct log() reporting
300: memset(&request_info, 0, sizeof(request_info));
1.294 moko 301:
302: char document_root_buf[MAX_STRING];
303: full_file_spec("", document_root_buf, sizeof(document_root_buf));
304: request_info.document_root = document_root_buf;
305: request_info.path_translated = filespec_to_process;
306: request_info.method = connection.method();
1.295 moko 307: request_info.query_string = connection.query();
308: request_info.uri = request_info.strip_absolute_uri(connection.uri());
309: request_info.content_type = connection.content_type();
310: request_info.content_length = connection.content_length();
311: request_info.cookie = info.get_env("HTTP_COOKIE");
312: request_info.mail_received = false;
1.294 moko 313: request_info.argv = argv_all + args_skip;
314:
315: // prepare to process request
316: Request request(info, request_info, String::Language(String::L_HTML|String::L_OPTIMIZE_BIT));
317: {
1.297 moko 318: // initing ::request ptr for signal handlers
1.294 moko 319: RequestController rc(&request);
1.307 moko 320: // process the request, we need @httpd-main in auto.p if filespec_to_process not specified
1.308 moko 321: request.core(locate_config() || !filespec_to_process ? config_filespec_cstr : NULL, strcasecmp(request_info.method, "HEAD")==0, String("httpd-main"));
1.297 moko 322: // clearing ::request in RequestController desctructor to prevent signal handlers from accessing invalid memory
1.294 moko 323: }
324: }
325:
1.308 moko 326: static void httpd_mode(){
1.296 moko 327: int sock = HTTPD_Server::bind(httpd_host_port);
1.294 moko 328:
1.297 moko 329: while(1){
1.303 moko 330: try {
331: HTTPD_Connection connection;
332: if(!connection.accept(sock, 5))
333: continue;
334:
335: SAPI_Info_HTTPD info(connection);
336:
337: try { // connection try
1.308 moko 338: connection_handler(info, connection);
1.303 moko 339: } catch(const Exception& e) { // exception in connection handling or unhandled exception
340: SAPI::log(info, "%s", e.comment());
341: SAPI::send_error(info, e.comment(), info.exception_http_status(e.type()));
342: }
343: // closing connection socket in HTTPD_Connection destructor
344: } catch(const Exception& e) { // exception in accept or send_error
345: SAPI::log(*sapiInfo, "%s", e.comment());
1.294 moko 346: }
347: }
348: }
1.231 paf 349:
1.294 moko 350: /** main workhorse */
351:
1.308 moko 352: static void real_parser_handler() {
1.280 moko 353: // init libraries
1.218 paf 354: pa_globals_init();
1.294 moko 355:
1.296 moko 356: if(httpd_host_port){
1.308 moko 357: httpd_mode();
1.294 moko 358: }
359:
360: const char* request_method=getenv("REQUEST_METHOD");
361:
1.308 moko 362: if(!filespec_to_process)
1.282 moko 363: SAPI::die("Parser/%s", PARSER_VERSION);
1.122 parser 364:
1.166 paf 365: char document_root_buf[MAX_STRING];
1.283 moko 366:
1.297 moko 367: // global request info
1.283 moko 368: request_info.path_translated = filespec_to_process;
369: request_info.method = request_method ? request_method : "GET";
370: request_info.query_string = MAYBE_RECONSTRUCT_IIS_STATUS_IN_QS(getenv("QUERY_STRING"));
371:
1.122 parser 372: if(cgi) {
1.284 moko 373: // obligatory
1.218 paf 374: const char* path_info=getenv("PATH_INFO");
1.214 paf 375: if(!path_info)
376: SAPI::die("CGI: illegal call (missing PATH_INFO)");
1.283 moko 377:
378: request_info.document_root = getenv("DOCUMENT_ROOT");
379: if(!request_info.document_root) {
1.285 moko 380: // IIS or fcgiwrap minimalistic setup
381: ssize_t prefix_len = strlen(filespec_to_process) - strlen(path_info);
382: if(prefix_len < 0 || strcmp(filespec_to_process + prefix_len, path_info) != 0)
383: SAPI::die("CGI: illegal call (invalid PATH_INFO in reinventing DOCUMENT_ROOT)");
384:
385: char* document_root = new(PointerFreeGC) char[prefix_len + 1/*0*/];
386: memcpy(document_root, filespec_to_process, prefix_len); document_root[prefix_len] = 0;
387: request_info.document_root = document_root;
1.283 moko 388: }
1.214 paf 389:
1.285 moko 390: request_info.uri = request_info.strip_absolute_uri(getenv("REQUEST_URI"));
1.283 moko 391: if(request_info.uri) { // apache & others stuck to standards
1.284 moko 392: // another obligatory
1.285 moko 393: const char* script_name = getenv("SCRIPT_NAME");
1.284 moko 394: if(!script_name)
395: SAPI::die("CGI: illegal call (missing SCRIPT_NAME)");
1.214 paf 396: /*
397: http://parser3/env.html?123 =OK
398: $request:uri=/env.html?123
399: REQUEST_URI='/env.html?123'
400: SCRIPT_NAME='/cgi-bin/parser3'
401: PATH_INFO='/env.html'
1.285 moko 402:
1.214 paf 403: http://parser3/cgi-bin/parser3/env.html?123 =ERROR
404: $request:uri=/cgi-bin/parser3/env.html?123
405: REQUEST_URI='/cgi-bin/parser3/env.html?123'
406: SCRIPT_NAME='/cgi-bin/parser3'
407: PATH_INFO='/env.html'
408: */
1.285 moko 409: size_t script_name_len = strlen(script_name);
410: size_t uri_len = strlen(request_info.uri);
1.283 moko 411: if(strncmp(request_info.uri, script_name, script_name_len)==0 && script_name_len != uri_len) // under IIS they are the same
1.214 paf 412: SAPI::die("CGI: illegal call (1)");
1.284 moko 413: } else { // fcgiwrap minimalistic setup
1.283 moko 414:
1.286 moko 415: if(request_info.query_string && *request_info.query_string) {
1.285 moko 416: char* reconstructed_uri = new(PointerFreeGC) char[strlen(path_info) + 1/*'?'*/+ strlen(request_info.query_string) + 1/*0*/];
1.283 moko 417: strcpy(reconstructed_uri, path_info);
418: strcat(reconstructed_uri, "?");
419: strcat(reconstructed_uri, request_info.query_string);
1.285 moko 420: request_info.uri = reconstructed_uri;
1.283 moko 421: } else
1.285 moko 422: request_info.uri = path_info;
1.214 paf 423: }
1.283 moko 424: } else{
425: full_file_spec("", document_root_buf, sizeof(document_root_buf));
1.285 moko 426: request_info.document_root = document_root_buf;
427: request_info.uri = "";
1.283 moko 428: }
1.122 parser 429:
1.283 moko 430: request_info.content_type = getenv("CONTENT_TYPE");
1.304 moko 431: request_info.content_length = pa_atoul(getenv("CONTENT_LENGTH"));
1.283 moko 432: request_info.cookie = getenv("HTTP_COOKIE");
433: request_info.mail_received = mail_received;
1.184 paf 434:
1.294 moko 435: request_info.argv = argv_all + args_skip;
1.245 misha 436:
1.233 paf 437: #ifdef PA_DEBUG_CGI_ENTRY_EXIT
1.297 moko 438: log("request_info: method=%s, uri=%s, q=%s, dr=%s, pt=%s, cookies=%s, cl=%u",
1.233 paf 439: request_info.method,
440: request_info.uri,
441: request_info.query_string,
442: request_info.document_root,
443: request_info.path_translated,
444: request_info.cookie,
445: request_info.content_length);
446: #endif
447:
1.122 parser 448: // prepare to process request
1.294 moko 449: Request request(*sapiInfo, request_info, cgi ? String::Language(String::L_HTML|String::L_OPTIMIZE_BIT) : String::L_AS_IS);
1.256 misha 450: {
1.297 moko 451: // initing ::request ptr for signal handlers
1.256 misha 452: RequestController rc(&request);
453: // process the request
1.306 moko 454: request.core(locate_config() ? config_filespec_cstr : NULL, strcasecmp(request_info.method, "HEAD")==0);
1.303 moko 455: // clearing ::request in RequestController destructor to prevent signal handlers from accessing invalid memory
1.122 parser 456: }
1.231 paf 457:
1.280 moko 458: // finalize libraries
1.225 paf 459: pa_globals_done();
1.218 paf 460: }
461:
1.231 paf 462: #ifdef PA_SUPPRESS_SYSTEM_EXCEPTION
1.308 moko 463: static const Exception call_real_parser_handler__do_PEH_return_it() {
1.231 paf 464: try {
1.308 moko 465: real_parser_handler();
1.231 paf 466: } catch(const Exception& e) {
467: return e;
1.122 parser 468: }
1.231 paf 469:
470: return Exception();
1.122 parser 471: }
1.272 moko 472:
1.308 moko 473: static void call_real_parser_handler__supress_system_exception() {
1.231 paf 474: Exception parser_exception;
475: LPEXCEPTION_POINTERS system_exception=0;
1.122 parser 476:
1.231 paf 477: __try {
1.308 moko 478: parser_exception=call_real_parser_handler__do_PEH_return_it();
1.288 moko 479: } __except ( (system_exception=GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER) {
1.231 paf 480: if(system_exception)
481: if(_EXCEPTION_RECORD *er=system_exception->ExceptionRecord)
1.272 moko 482: throw Exception("system", 0, "0x%08X at 0x%08X", er->ExceptionCode, er->ExceptionAddress);
1.218 paf 483: else
1.272 moko 484: throw Exception("system", 0, "<no exception record>");
1.218 paf 485: else
1.272 moko 486: throw Exception("system", 0, "<no exception information>");
1.231 paf 487: }
488:
489: if(parser_exception)
490: throw Exception(parser_exception);
491: }
1.273 moko 492:
493: #define REAL_PARSER_HANDLER call_real_parser_handler__supress_system_exception
494: #else
495: #define REAL_PARSER_HANDLER real_parser_handler
1.218 paf 496: #endif
1.131 paf 497:
1.218 paf 498: static void usage(const char* program) {
1.188 paf 499: printf(
1.235 paf 500: "Parser/%s\n"
1.277 moko 501: "Copyright (c) 2001-2017 Art. Lebedev Studio (http://www.artlebedev.com)\n"
1.184 paf 502: "Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)\n"
503: "\n"
1.307 moko 504: "Usage: %s [options] [file]\n"
1.184 paf 505: "Options are:\n"
1.185 paf 506: #ifdef WITH_MAILRECEIVE
1.193 paf 507: " -m Parse mail, put received letter to $mail:received\n"
1.184 paf 508: #endif
1.193 paf 509: " -f config_file Use this config file (/path/to/auto.p)\n"
1.296 moko 510: " -p [host:]port Start web server on this port\n"
1.272 moko 511: " -h Display usage information (this message)\n",
512: PARSER_VERSION,
1.184 paf 513: program);
514: exit(EINVAL);
515: }
516:
1.294 moko 517:
1.249 misha 518: int main(int argc, char *argv[]) {
1.233 paf 519: #ifdef PA_DEBUG_CGI_ENTRY_EXIT
520: log("main: entry");
521: #endif
1.217 paf 522:
1.294 moko 523: argv_all=argv;
524: umask(2);
525:
526: // were we started as CGI?
527: cgi=(getenv("SERVER_SOFTWARE") || getenv("SERVER_NAME") || getenv("GATEWAY_INTERFACE") || getenv("REQUEST_METHOD")) && !getenv("PARSER_VERSION");
528: sapiInfo = cgi ? new SAPI_Info_CGI() : new SAPI_Info();
529:
1.203 paf 530: #ifdef SIGUSR1
1.205 paf 531: if(signal(SIGUSR1, SIGUSR1_handler)==SIG_ERR)
1.203 paf 532: SAPI::die("Can not set handler for SIGUSR1");
533: #endif
534: #ifdef SIGPIPE
1.205 paf 535: if(signal(SIGPIPE, SIGPIPE_handler)==SIG_ERR)
1.203 paf 536: SAPI::die("Can not set handler for SIGPIPE");
537: #endif
538:
1.301 moko 539: char *raw_filespec_to_process = NULL;
1.210 paf 540: if(cgi) {
1.184 paf 541: raw_filespec_to_process=getenv("PATH_TRANSLATED");
1.210 paf 542: } else {
1.250 misha 543: int optind=1;
1.245 misha 544: while(optind < argc){
545: char *carg = argv[optind];
546: if(carg[0] != '-')
1.184 paf 547: break;
1.245 misha 548:
549: for(size_t k = 1; k < strlen(carg); k++){
550: char c = carg[k];
551: switch (c) {
552: case 'h':
553: usage(argv[0]);
554: break;
555: case 'f':
556: if(optind < argc - 1){
557: optind++;
558: config_filespec_cstr=argv[optind];
559: }
560: break;
1.294 moko 561: case 'p':
562: if(optind < argc - 1){
563: optind++;
1.296 moko 564: httpd_host_port=argv[optind];
1.294 moko 565: }
566: break;
1.185 paf 567: #ifdef WITH_MAILRECEIVE
1.245 misha 568: case 'm':
569: mail_received=true;
570: break;
571: #endif
572: default:
573: fprintf(stderr, "%s: invalid option '%c'\n", argv[0], c);
574: usage(argv[0]);
575: break;
576: }
1.184 paf 577: }
1.245 misha 578: optind++;
1.184 paf 579: }
1.245 misha 580:
581: if (optind > argc - 1) {
1.296 moko 582: if(!httpd_host_port) {
1.294 moko 583: fprintf(stderr, "%s: file not specified\n", argv[0]);
584: usage(argv[0]);
585: }
586: } else {
587: raw_filespec_to_process=argv[optind];
1.10 paf 588: }
1.245 misha 589: args_skip=optind;
1.294 moko 590:
1.296 moko 591: if (httpd_host_port && mail_received) {
1.294 moko 592: fprintf(stderr, "%s: -p and -m options should not be used together\n", argv[0]);
593: usage(argv[0]);
594: }
1.10 paf 595: }
596:
1.264 moko 597: #ifdef _MSC_VER
1.100 parser 598: setmode(fileno(stdin), _O_BINARY);
599: setmode(fileno(stdout), _O_BINARY);
600: setmode(fileno(stderr), _O_BINARY);
601: #endif
602:
1.218 paf 603: #if defined(_MSC_VER) && defined(_DEBUG)
1.148 paf 604: // Get current flag
605: int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
606:
607: // Turn on leak-checking bit
608: tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
609:
610: // Set flag to the new value
611: _CrtSetDbgFlag( tmpFlag );
1.138 paf 612:
1.218 paf 613: _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
614: _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
1.138 paf 615: #endif
616:
1.308 moko 617: char filespec_to_process_buf[MAX_STRING];
618: if(raw_filespec_to_process && *raw_filespec_to_process){
619: full_file_spec(raw_filespec_to_process, filespec_to_process_buf, sizeof(filespec_to_process_buf));
620: filespec_to_process=filespec_to_process_buf;
621: }
1.10 paf 622:
1.122 parser 623: try { // global try
1.308 moko 624: REAL_PARSER_HANDLER();
1.292 moko 625: } catch(const Exception& e) { // exception in unhandled exception
1.298 moko 626: SAPI::die("%s", e.comment());
1.16 paf 627: }
1.109 parser 628:
1.233 paf 629: #ifdef PA_DEBUG_CGI_ENTRY_EXIT
630: log("main: successful return");
631: #endif
1.299 moko 632: return sapiInfo->http_response_code < 100 ? sapiInfo->http_response_code : 0;
1.1 paf 633: }
E-mail: