Annotation of parser3/src/targets/cgi/parser3.C, revision 1.122
1.27 paf 1: /** @file
2: Parser: scripting and CGI main.
3:
1.43 paf 4: Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com)
1.113 parser 5: Author: Alexander Petrosyan <paf@design.ru>(http://design.ru/paf)
1.27 paf 6:
1.122 ! parser 7: $Id: parser3.C,v 1.121 2001/10/13 17:42:52 parser Exp $
1.1 paf 8: */
9:
1.40 paf 10: #include "pa_config_includes.h"
1.3 paf 11:
12: #ifdef WIN32
13: # include <windows.h>
14: #endif
1.27 paf 15:
1.37 paf 16: #include "pa_sapi.h"
1.76 paf 17: #include "classes.h"
1.24 paf 18: #include "pa_common.h"
1.2 paf 19: #include "pa_request.h"
1.57 paf 20: #include "pa_socks.h"
1.68 paf 21: #include "pa_version.h"
1.69 paf 22:
1.120 parser 23: #ifdef XML
24: #include <XalanTransformer/XalanCAPI.h>
25: #endif
26:
1.84 parser 27: //#define DEBUG_POOL_MALLOC
28:
1.109 parser 29: // consts
1.113 parser 30:
31: extern const char *main_RCSIds[];
1.116 parser 32: #ifdef USE_SMTP
1.113 parser 33: extern const char *smtp_RCSIds[];
1.114 parser 34: #endif
1.113 parser 35: extern const char *gd_RCSIds[];
36: extern const char *classes_RCSIds[];
37: extern const char *types_RCSIds[];
1.115 parser 38: extern const char *parser3_RCSIds[];
1.119 parser 39: #ifdef XML
40: extern const char *xalan_patched_RCSIds[];
41: #endif
1.113 parser 42: const char **RCSIds[]={
43: main_RCSIds,
1.116 parser 44: #ifdef USE_SMTP
1.113 parser 45: smtp_RCSIds,
1.114 parser 46: #endif
1.113 parser 47: gd_RCSIds,
48: classes_RCSIds,
49: types_RCSIds,
1.115 parser 50: parser3_RCSIds,
1.118 parser 51: #ifdef XML
52: xalan_patched_RCSIds,
53: #endif
1.113 parser 54: 0
55: };
1.84 parser 56:
1.42 paf 57: /// IIS refuses to read bigger chunks
58: const size_t READ_POST_CHUNK_SIZE=0x400*0x400; // 1M
59:
1.45 paf 60: const char *argv0;
1.42 paf 61: Pool pool(0); // global pool [dont describe to doxygen: it confuses it with param names]
1.27 paf 62: bool cgi; ///< we were started as CGI?
1.5 paf 63:
1.46 paf 64: // SAPI
1.86 parser 65:
66: // appends to parser3.log located beside my binary if openable, to stderr otherwize
1.122 ! parser 67: void SAPI::log(Pool& , const char *fmt, ...) {
1.61 paf 68: bool opened;
69: FILE *f=0;
70:
71: if(argv0) {
72: // beside by binary
73: char file_spec[MAX_STRING];
1.98 parser 74: strncpy(file_spec, argv0, MAX_STRING-1); file_spec[MAX_STRING-1]=0; // filespec of my binary
1.61 paf 75: rsplit(file_spec, '/'); rsplit(file_spec, '\\');// strip filename
76: strcat(file_spec, "/parser3.log");
77: f=fopen(file_spec, "at");
78: }
79: opened=f!=0;
80: if(!opened)
81: f=stderr;
82:
83: // prefix
84: time_t t=time(0);
85: const char *stamp=ctime(&t);
86: fprintf(f, "[%.*s] ", strlen(stamp)-1, stamp);
87: // message
88: va_list args;
89: va_start(args,fmt);
1.117 parser 90:
91: char buf[MAX_STRING];
92: size_t size=vsnprintf(buf, MAX_STRING, fmt, args);
93: remove_crlf(buf, buf+size);
94:
95: fwrite(buf, size, 1, f);
1.61 paf 96: va_end(args);
97: // newline
98: fprintf(f, "\n");
99:
100: if(opened)
101: fclose(f);
1.85 parser 102: else
103: fflush(f);
1.61 paf 104: }
105:
1.122 ! parser 106: const char *SAPI::get_env(Pool& , const char *name) {
1.109 parser 107: return getenv(name);
1.28 paf 108: }
109:
1.122 ! parser 110: size_t SAPI::read_post(Pool& , char *buf, size_t max_bytes) {
1.59 paf 111: size_t read_size=0;
1.12 paf 112: do {
1.36 paf 113: int chunk_size=read(fileno(stdin),
1.42 paf 114: buf+read_size, min(READ_POST_CHUNK_SIZE, max_bytes-read_size));
1.12 paf 115: if(chunk_size<0)
116: break;
117: read_size+=chunk_size;
118: } while(read_size<max_bytes);
119:
120: return read_size;
1.10 paf 121: }
122:
1.122 ! parser 123: void SAPI::add_header_attribute(Pool& , const char *key, const char *value) {
1.68 paf 124: if(cgi)
1.20 paf 125: printf("%s: %s\n", key, value);
1.19 paf 126: }
127:
1.56 paf 128: /// @todo intelligent cache-control
1.122 ! parser 129: void SAPI::send_header(Pool& ) {
1.33 paf 130: if(cgi) {
1.55 paf 131: puts("expires: Fri, 23 Mar 2001 09:32:23 GMT");
1.33 paf 132:
133: // header | body delimiter
1.20 paf 134: puts("");
1.33 paf 135: }
1.30 paf 136: }
1.20 paf 137:
1.122 ! parser 138: void SAPI::send_body(Pool& , const void *buf, size_t size) {
1.19 paf 139: stdout_write(buf, size);
1.58 paf 140: }
141:
1.97 parser 142: //
143:
144: char *full_file_spec(char *file_name) {
1.108 parser 145: if(file_name && !strchr(file_name, '/')) {
1.97 parser 146: static char cwd[MAX_STRING]; getcwd(cwd, MAX_STRING);
147: static char buf[MAX_STRING];
148: snprintf(buf, MAX_STRING, "%s/%s", cwd, file_name);
149: return buf;
150: }
151: return file_name;
152: }
153:
1.40 paf 154: /**
1.122 ! parser 155: main workhorse
1.19 paf 156:
1.122 ! parser 157: @todo
1.40 paf 158: IIS: remove trailing default-document[index.html] from $request.uri.
159: to do that we need to consult metabase,
160: wich is tested but seems slow.
161: */
1.122 ! parser 162: void real_parser_handler(
! 163: const char *filespec_to_process,
! 164: const char *request_method, bool header_only) {
! 165: // init socks
! 166: init_socks(pool);
! 167:
! 168: #ifdef XML
! 169: /**
! 170: * Initialize Xerces and Xalan.
! 171: *
! 172: * Should be called only once per process before making
! 173: * any other API calls.
! 174: */
! 175: //_asm int 3;
! 176: XalanInitialize();
! 177: #endif
! 178:
! 179: // init global classes
! 180: init_methoded_array(pool);
! 181: // init global variables
! 182: pa_globals_init(pool);
! 183:
! 184: if(!filespec_to_process)
! 185: throw Exception(0, 0,
! 186: 0,
! 187: "Parser/%s", PARSER_VERSION);
! 188:
! 189: // Request info
! 190: Request::Info request_info;
! 191: if(cgi) {
! 192: if(const char *env_document_root=SAPI::get_env(pool, "DOCUMENT_ROOT"))
! 193: request_info.document_root=env_document_root;
! 194: else if(const char *path_info=SAPI::get_env(pool, "PATH_INFO")) {
! 195: // IIS
! 196: size_t len=strlen(filespec_to_process)-strlen(path_info);
! 197: char *buf=(char *)pool.malloc(len+1);
! 198: memcpy(buf, filespec_to_process, len); buf[len]=0;
! 199: request_info.document_root=buf;
! 200: } else
! 201: throw Exception(0, 0,
! 202: 0,
! 203: "CGI: no PATH_INFO defined(in reinventing DOCUMENT_ROOT)");
! 204: } else {
! 205: static char buf[MAX_STRING];
! 206: strncpy(buf, filespec_to_process, MAX_STRING-1); buf[MAX_STRING-1]=0;
! 207: if(rsplit(buf, '/') || rsplit(buf, '\\')) // strip filename
! 208: request_info.document_root=buf;
! 209: else
! 210: request_info.document_root="";
! 211: }
! 212: request_info.path_translated=filespec_to_process;
! 213: request_info.method=request_method ? request_method : "GET";
! 214: const char *query_string=SAPI::get_env(pool, "QUERY_STRING");
! 215: request_info.query_string=query_string;
! 216: if(cgi) {
! 217: if(const char *env_request_uri=SAPI::get_env(pool, "REQUEST_URI"))
! 218: request_info.uri=env_request_uri;
! 219: else if(const char *path_info=SAPI::get_env(pool, "PATH_INFO"))
! 220: if(query_string) {
! 221: char *reconstructed_uri=(char *)pool.malloc(
! 222: strlen(path_info)+1/*'?'*/+
! 223: strlen(query_string)+1/*0*/);
! 224: strcpy(reconstructed_uri, path_info);
! 225: strcat(reconstructed_uri, "?");
! 226: strcat(reconstructed_uri, query_string);
! 227: request_info.uri=reconstructed_uri;
! 228: } else
! 229: request_info.uri=path_info;
! 230: else
! 231: throw Exception(0, 0,
! 232: 0,
! 233: "CGI: no PATH_INFO defined(in reinventing REQUEST_URI)");
! 234:
! 235: if(const char *script_name=SAPI::get_env(pool, "SCRIPT_NAME")) {
! 236: size_t script_name_len=strlen(script_name);
! 237: size_t uri_len=strlen(request_info.uri);
! 238: if(strncmp(request_info.uri,script_name, script_name_len)==0 &&
! 239: script_name_len != uri_len) // under IIS they are the same
! 240: throw Exception(0, 0,
! 241: 0,
! 242: "CGI: illegal call");
! 243: }
! 244: } else
! 245: request_info.uri=0;
! 246:
! 247: request_info.content_type=SAPI::get_env(pool, "CONTENT_TYPE");
! 248: const char *content_length=SAPI::get_env(pool, "CONTENT_LENGTH");
! 249: request_info.content_length=(content_length?atoi(content_length):0);
! 250: request_info.cookie=SAPI::get_env(pool, "HTTP_COOKIE");
! 251: request_info.user_agent=SAPI::get_env(pool, "HTTP_USER_AGENT");
! 252:
! 253: // prepare to process request
! 254: Request request(pool,
! 255: request_info,
! 256: cgi ? String::UL_USER_HTML : String::UL_AS_IS
! 257: );
! 258:
! 259: // some root-controlled location
! 260: #ifdef SYSCONFDIR
! 261: const char *root_config_filespec=SYSCONFDIR "/" CONFIG_FILE_NAME;
! 262: #else
! 263: # ifdef WIN32
! 264: // c:\windows
! 265: char root_config_path[MAX_STRING];
! 266: GetWindowsDirectory(root_config_path, MAX_STRING);
! 267:
! 268: char root_config_filespec[MAX_STRING];
! 269: snprintf(root_config_filespec, MAX_STRING,
! 270: "%s/%s",
! 271: root_config_path, CONFIG_FILE_NAME);
! 272: # else
! 273: #error must be compiled either configure/make or MSVC++
! 274: # endif
! 275: #endif
! 276:
! 277: // beside by binary
! 278: // @todo full path, not ./!
! 279: static char site_config_path[MAX_STRING];
! 280: strncpy(site_config_path, argv0, MAX_STRING-1); site_config_path[MAX_STRING-1]=0; // filespec of my binary
! 281: if(!(
! 282: rsplit(site_config_path, '/') ||
! 283: rsplit(site_config_path, '\\'))) { // strip filename
! 284: // no path, just filename
! 285: site_config_path[0]='.'; site_config_path[1]=0;
! 286: }
! 287:
! 288: char site_config_filespec[MAX_STRING];
! 289: snprintf(site_config_filespec, MAX_STRING,
! 290: "%s/%s",
! 291: site_config_path, CONFIG_FILE_NAME);
! 292:
! 293: // process the request
! 294: request.core(
! 295: root_config_filespec, false,
! 296: site_config_filespec, false,
! 297: header_only);
! 298:
! 299: //
! 300: done_socks();
! 301:
! 302: #ifdef DEBUG_POOL_MALLOC
! 303: extern void log_pool_stats(Pool& pool);
! 304: log_pool_stats(pool);
! 305: #endif
! 306: }
! 307:
! 308: void call_real_parser_handler__do_SEH(
! 309: const char *filespec_to_process,
! 310: const char *request_method, bool header_only) {
! 311: #ifdef WIN32
! 312: LPEXCEPTION_POINTERS system_exception=0;
! 313: __try {
! 314: #endif
! 315: real_parser_handler(
! 316: filespec_to_process,
! 317: request_method, header_only);
! 318:
! 319: #if _MSC_VER
! 320: } __except (
! 321: (system_exception=GetExceptionInformation()),
! 322: EXCEPTION_EXECUTE_HANDLER) {
! 323:
! 324: if(system_exception)
! 325: if(_EXCEPTION_RECORD *er=system_exception->ExceptionRecord)
! 326: throw Exception(0, 0,
! 327: 0,
! 328: "Exception 0x%08X at 0x%08X", er->ExceptionCode, er->ExceptionAddress);
! 329: else
! 330: throw Exception(0, 0, 0, "Exception <no exception record>");
! 331: else
! 332: throw Exception(0, 0, 0, "Exception <no exception information>");
! 333: }
! 334: #endif
! 335: }
! 336:
1.5 paf 337: int main(int argc, char *argv[]) {
1.109 parser 338: int result;
1.45 paf 339: argv0=argv[0];
340:
1.32 paf 341: umask(2);
342:
1.3 paf 343: // were we started as CGI?
1.20 paf 344: cgi=
1.109 parser 345: getenv("SERVER_SOFTWARE") ||
346: getenv("SERVER_NAME") ||
347: getenv("GATEWAY_INTERFACE") ||
348: getenv("REQUEST_METHOD");
1.5 paf 349:
1.10 paf 350: if(!cgi) {
351: if(argc<2) {
1.69 paf 352: printf(
1.100 parser 353: "Parser/%s Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com)\n"
354: "Author: Alexander Petrosyan <paf@design.ru>(http://design.ru/paf)\n"
355: "\n"
356: "Usage: %s <file>\n",
1.69 paf 357: PARSER_VERSION,
358: argv0?argv0:"parser3");
1.67 paf 359: return 1;
1.10 paf 360: }
361: }
362:
1.100 parser 363: #ifdef WIN32
364: setmode(fileno(stdin), _O_BINARY);
365: setmode(fileno(stdout), _O_BINARY);
366: setmode(fileno(stderr), _O_BINARY);
367: #endif
368:
1.109 parser 369: char *filespec_to_process=cgi?getenv("PATH_TRANSLATED"):argv[1];
1.36 paf 370: #ifdef WIN32
1.43 paf 371: back_slashes_to_slashes(filespec_to_process);
1.36 paf 372: #endif
1.97 parser 373: filespec_to_process=full_file_spec(filespec_to_process);
1.10 paf 374:
1.109 parser 375: const char *request_method=getenv("REQUEST_METHOD");
1.35 paf 376: bool header_only=request_method && strcasecmp(request_method, "HEAD")==0;
1.122 ! parser 377: try { // global try
! 378: call_real_parser_handler__do_SEH(
! 379: filespec_to_process,
! 380: request_method, header_only);
1.100 parser 381:
1.16 paf 382: // successful finish
1.109 parser 383: result=0;
1.122 ! parser 384: } catch(const Exception& e) { // global problem
1.44 paf 385: // don't allocate anything on pool here:
386: // possible pool' exception not catch-ed now
387: // and there could be out-of-memory exception
1.43 paf 388:
1.19 paf 389: const char *body=e.comment();
1.44 paf 390: // log it
391: SAPI::log(pool, "exception in request exception handler: %s", body);
392:
393: //
1.19 paf 394: int content_length=strlen(body);
1.5 paf 395:
1.35 paf 396: // prepare header
1.37 paf 397: SAPI::add_header_attribute(pool, "content-type", "text/plain");
1.19 paf 398: char content_length_cstr[MAX_NUMBER];
1.60 paf 399: snprintf(content_length_cstr, MAX_NUMBER, "%u", content_length);
1.37 paf 400: SAPI::add_header_attribute(pool, "content-length", content_length_cstr);
1.35 paf 401:
402: // send header
1.37 paf 403: SAPI::send_header(pool);
1.19 paf 404:
405: // body
1.35 paf 406: if(!header_only)
1.37 paf 407: SAPI::send_body(pool, body, content_length);
1.94 parser 408:
1.16 paf 409: // unsuccessful finish
1.109 parser 410: result=1;
1.16 paf 411: }
1.122 ! parser 412:
1.109 parser 413:
414: #ifndef WIN32
415: //
416: if(!cgi)
417: SAPI::send_body(pool, "\n", 1);
418: #endif
419: return result;
1.1 paf 420: }
E-mail: