Annotation of parser3/src/targets/cgi/parser3.C, revision 1.123
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.123 ! parser 7: $Id: parser3.C,v 1.122 2001/10/19 12:43:30 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) {
1.123 ! parser 311: #if _MSC_VER & !defined(_DEBUG)
1.122 parser 312: LPEXCEPTION_POINTERS system_exception=0;
313: __try {
314: #endif
315: real_parser_handler(
316: filespec_to_process,
317: request_method, header_only);
318:
1.123 ! parser 319: #if _MSC_VER & !defined(_DEBUG)
1.122 parser 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: