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