Annotation of parser3/src/main/pa_request.C, revision 1.159
1.54 paf 1: /** @file
1.55 paf 2: Parser: request class main part. @see compile.C and execute.C.
3:
1.9 paf 4: Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
1.156 parser 5: Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)
1.55 paf 6:
1.159 ! parser 7: $Id: pa_request.C,v 1.158 2001/09/30 09:56:43 parser Exp $
1.1 paf 8: */
9:
1.70 paf 10: #include "pa_config_includes.h"
1.19 paf 11:
1.117 paf 12: #include "pcre.h"
13: #include "internal.h"
1.132 parser 14: extern "C" unsigned char pcre_default_tables[]; // pcre/chartables.c
1.96 paf 15:
1.69 paf 16: #include "pa_sapi.h"
1.53 paf 17: #include "pa_common.h"
1.1 paf 18: #include "pa_request.h"
1.3 paf 19: #include "pa_wwrapper.h"
20: #include "pa_vclass.h"
1.31 paf 21: #include "pa_globals.h"
1.30 paf 22: #include "pa_vint.h"
1.112 paf 23: #include "pa_vmethod_frame.h"
1.32 paf 24: #include "pa_types.h"
1.78 paf 25: #include "pa_vtable.h"
1.90 paf 26: #include "pa_vfile.h"
1.147 parser 27: #include "pa_dictionary.h"
1.3 paf 28:
1.159 ! parser 29: #ifdef XML
! 30: # include <util/XercesDefs.hpp>
! 31: # include <util/TransENameMap.hpp>
! 32: # include <util/XML256TableTranscoder.hpp>
! 33: # include <util/PlatformUtils.hpp>
! 34: #endif
! 35:
1.82 paf 36: /// content type of exception response, when no @MAIN:exception handler defined
37: const char *UNHANDLED_EXCEPTION_CONTENT_TYPE="text/plain";
38:
39: /// content type of response when no $MAIN:defaults.content-type defined
40: const char *DEFAULT_CONTENT_TYPE="text/html";
1.144 parser 41: const char *ORIGINS_CONTENT_TYPE="text/plain";
1.82 paf 42:
1.123 paf 43: Methoded *MOP_create(Pool&);
44:
1.117 paf 45:
1.158 parser 46: inline void prepare_case_tables(unsigned char *tables) {
47: unsigned char *lcc_table=tables+lcc_offset;
48: unsigned char *fcc_table=tables+fcc_offset;
49: for(int i=0; i<0x100; i++)
50: lcc_table[i]=fcc_table[i]=i;
1.117 paf 51: }
1.158 parser 52: inline void cstr2ctypes(unsigned char *tables, const unsigned char *cstr,
1.117 paf 53: unsigned char bit) {
54: unsigned char *ctypes_table=tables+ctypes_offset;
55: ctypes_table[0]=bit;
56: for(; *cstr; cstr++) {
57: unsigned char c=*cstr;
58: ctypes_table[c]|=bit;
59: }
60: }
1.158 parser 61: inline unsigned int to_wchar_code(const String *s) {
62: if(!s || s->size()==0)
63: return 0;
64: if(s->size()==1)
65: return (unsigned int)s->first_char();
66: return (unsigned int)s->as_int();
67: }
68: inline bool to_bool(const String *s) {
69: return s && s->size()!=0;
70: }
71: static void element2ctypes(unsigned char c, bool belongs,
72: unsigned char *tables, unsigned char bit, int group_offset=-1) {
73: if(!belongs)
74: return;
75:
76: unsigned char *ctypes_table=tables+ctypes_offset;
77:
78: ctypes_table[c]|=bit;
79: if(group_offset>=0)
80: tables[cbits_offset+group_offset+c/8] |= 1 << (c%8);
81: }
82: static void element2case(unsigned char from, unsigned char to,
83: unsigned char *tables) {
84: if(!to)
85: return;
86:
1.117 paf 87: unsigned char *lcc_table=tables+lcc_offset;
88: unsigned char *fcc_table=tables+fcc_offset;
1.158 parser 89: lcc_table[from]=to;
90: fcc_table[from]=to; fcc_table[to]=from;
1.117 paf 91: }
92:
1.159 ! parser 93: #ifndef DOXYGEN
! 94: struct CTYPE_Tables {
! 95: // pcre_tables
! 96: unsigned char *pcre_tables;
! 97: #ifdef XML
! 98: // transcoder
! 99: XMLCh *fromTable;
! 100: XMLTransService::TransRec *toTable;
! 101: unsigned int toTableSz;
! 102: #endif
! 103: };
! 104: #endif
! 105:
! 106: static void ctype_table_row_to_CTYPE_tables(Array::Item *value, void *info) {
1.158 parser 107: Array& row=*static_cast<Array *>(value);
1.159 ! parser 108: CTYPE_Tables& tables=*static_cast<CTYPE_Tables *>(info);
1.158 parser 109:
110: // char white-space digit hex-digit letter word lowercase unicode1 unicode2
111: unsigned int c=to_wchar_code(row.get_string(0));
112:
1.159 ! parser 113: // pcre_tables
! 114: element2ctypes(c, to_bool(row.get_string(1)), tables.pcre_tables, ctype_space, cbit_space);
! 115: element2ctypes(c, to_bool(row.get_string(2)), tables.pcre_tables, ctype_digit, cbit_digit);
! 116: element2ctypes(c, to_bool(row.get_string(3)), tables.pcre_tables, ctype_xdigit);
! 117: element2ctypes(c, to_bool(row.get_string(4)), tables.pcre_tables, ctype_letter);
! 118: element2ctypes(c, to_bool(row.get_string(5)), tables.pcre_tables, ctype_word, cbit_word);
! 119: element2case(c, to_wchar_code(row.get_string(6)), tables.pcre_tables);
! 120:
! 121: #ifdef XML
! 122: XMLCh unicode1=row.size()>7?(XMLCh)to_wchar_code(row.get_string(7)):0;
! 123: XMLCh unicode2=row.size()>8?(XMLCh)to_wchar_code(row.get_string(8)):0;
! 124: tables.toTable[tables.toTableSz].intCh=unicode1?unicode1:(XMLCh)c;
! 125: tables.toTable[tables.toTableSz].extCh=(XMLByte)c;
! 126: tables.toTableSz++;
! 127: if(unicode2) {
! 128: tables.toTable[tables.toTableSz].intCh=unicode2;
! 129: tables.toTable[tables.toTableSz].extCh=(XMLByte)c;
! 130: tables.toTableSz++;
! 131: }
! 132: #endif
! 133: }
! 134: static int sort_cmp_Trans_rec_intCh(const void *a, const void *b) {
! 135: const XMLCh ca=static_cast<const XMLTransService::TransRec *>(a)->intCh;
! 136: const XMLCh cb=static_cast<const XMLTransService::TransRec *>(b)->intCh;
! 137: // move zeros to end of table
! 138: if(ca==0)
! 139: return +1;
! 140: if(cb==0)
! 141: return -1;
! 142:
! 143: return ca-cb;
1.158 parser 144: }
145:
1.159 ! parser 146:
! 147: #ifdef XML
! 148: template <class TType> class ENameMapFor2 : public ENameMap
! 149: {
! 150: public :
! 151: // -----------------------------------------------------------------------
! 152: // Constructors and Destructor
! 153: // -----------------------------------------------------------------------
! 154: ENameMapFor2(
! 155: const XMLCh* const encodingName
! 156: , const XMLCh* const fromTable
! 157: , const XMLTransService::TransRec* const toTable
! 158: , const unsigned int toTableSize
! 159: ) : ENameMap(encodingName),
! 160: ffromTable(fromTable),
! 161: ftoTable(toTable),
! 162: ftoTableSize(toTableSize) {}
! 163: ~ENameMapFor2() {}
! 164:
! 165: // -----------------------------------------------------------------------
! 166: // Implementation of virtual factory method
! 167: // -----------------------------------------------------------------------
! 168: virtual XMLTranscoder* makeNew(const unsigned int blockSize) const {
! 169: return new TType(
! 170: getKey(),
! 171: blockSize,
! 172: ffromTable,
! 173: ftoTable, ftoTableSize);
! 174: }
! 175: private:
! 176: const XMLCh* const ffromTable;
! 177: const XMLTransService::TransRec* const ftoTable;
! 178: const unsigned int ftoTableSize;
! 179:
! 180: private :
! 181: // -----------------------------------------------------------------------
! 182: // Unimplemented constructors and operators
! 183: // -----------------------------------------------------------------------
! 184: ENameMapFor2();
! 185: ENameMapFor2(const ENameMapFor2<TType>&);
! 186: void operator=(const ENameMapFor2<TType>&);
! 187: };
! 188:
! 189: class XML256TableTranscoder2 : public XML256TableTranscoder
! 190: {
! 191: public :
! 192: XML256TableTranscoder2(
! 193: const XMLCh* const encodingName
! 194: , const unsigned int blockSize
! 195: , const XMLCh* const fromTable
! 196: , const XMLTransService::TransRec* const toTable
! 197: , const unsigned int toTableSize
! 198: ) : XML256TableTranscoder(encodingName, blockSize, fromTable, toTable, toTableSize) {}
! 199:
! 200: private :
! 201: XML256TableTranscoder2();
! 202: XML256TableTranscoder2(const XML256TableTranscoder2&);
! 203: void operator=(const XML256TableTranscoder2&);
! 204: };
! 205: #endif
! 206:
1.158 parser 207: static void load_ctype_for_charset(const Hash::Key& akey, Hash::Val *avalue,
208: void *info) {
209: Hash& CTYPE=*static_cast<Hash *>(info);
210: Pool& pool=CTYPE.pool();
211:
1.159 ! parser 212: CTYPE_Tables tables={
! 213: // pcre_tables
! 214: // lowcase, flipcase, bits digit+word+whitespace, masks
! 215: (unsigned char *)pool.calloc(tables_length) // pcre_tables
! 216: #ifdef XML
! 217: // transcoder
! 218: , (XMLCh *)pool.calloc(sizeof(XMLCh)*0x100) // fromTable
! 219: , 0 // toTable
! 220: , 0 // toTableSz
! 221: #endif
! 222: };
! 223: prepare_case_tables(tables.pcre_tables);
! 224: cstr2ctypes(tables.pcre_tables, (const unsigned char *)"*+?{^.$|()[", ctype_meta);
1.158 parser 225:
1.159 ! parser 226: // fill tables
1.158 parser 227: Value& value=*static_cast<Value *>(avalue);
228: if(Table *table=value.get_table()) {
1.159 ! parser 229: #ifdef XML
! 230: tables.toTable=(XMLTransService::TransRec *)pool.calloc(
! 231: sizeof(XMLTransService::TransRec)*table->size()*2);
! 232: #endif
! 233: table->for_each(ctype_table_row_to_CTYPE_tables, &tables);
! 234: #ifdef XML
! 235: // sort by the Unicode code point
! 236: _qsort(tables.toTable, tables.toTableSz, sizeof(*tables.toTable),
! 237: sort_cmp_Trans_rec_intCh);
! 238: #endif
! 239: } else
1.158 parser 240: PTHROW(0, 0,
241: &value.name(),
242: "must be hash");
243:
1.159 ! parser 244: // charset->pcre_tables
! 245: CTYPE.put(akey, tables.pcre_tables);
! 246:
! 247: #ifdef XML
! 248: // charset->transcoder
! 249: XalanDOMString skey(akey.cstr());
! 250: const XMLCh* const auto_encoding_cstr=skey.c_str();
! 251: int size=sizeof(XMLCh)*(skey.size()+1);
! 252: XMLCh* pool_encoding_cstr=(XMLCh*)malloc(size);
! 253: memcpy(pool_encoding_cstr, auto_encoding_cstr, size);
! 254: XMLString::upperCase(pool_encoding_cstr);
! 255:
! 256: XMLPlatformUtils::fgTransService->addEncoding(
! 257: pool_encoding_cstr,
! 258: new ENameMapFor2<XML256TableTranscoder2>(
! 259: pool_encoding_cstr
! 260: , tables.fromTable
! 261: , tables.toTable
! 262: , tables.toTableSz
! 263: ));
! 264: // delete sencoding; somehow
! 265: #endif
1.157 parser 266: }
267:
268: //
269: Request::Request(Pool& apool,
270: Info& ainfo,
271: String::Untaint_lang adefault_lang) : Pooled(apool),
272: stack(apool),
273: OP(*MOP_create(apool)),
274: env(apool),
275: form(apool),
276: math(apool),
277: request(apool, *this),
278: response(apool),
279: cookie(apool),
280: fclasses(apool),
1.158 parser 281: CTYPE(apool),
1.157 parser 282: fdefault_lang(adefault_lang), flang(adefault_lang),
283: info(ainfo),
284: post_data(0), post_size(0),
285: used_files(apool),
286: default_content_type(0),
287: mime_types(0),
288: main_class(0),
289: connection(0),
290: classes_conf(apool),
1.158 parser 291: anti_endless_execute_recoursion(0)
1.157 parser 292: {
293: /// directly used
294: // operators
295: OP.register_directly_used(*this);
296: // classes:
297: // table, file, random, mail, image, ...
298: methoded_array->register_directly_used(*this);
299:
300: /// methodless
301: // env class
302: classes().put(*NEW String(pool(), ENV_CLASS_NAME), &env);
303: // request class
304: classes().put(*NEW String(pool(), REQUEST_CLASS_NAME), &request);
305: // cookie class
306: classes().put(*NEW String(pool(), COOKIE_CLASS_NAME), &cookie);
307:
308: /// methoded
309: // response class
310: classes().put(response.get_class()->name(), &response);
311:
312: /// bases used
313: // form class
314: classes().put(form.get_class()->base()->name(), &form);
315: // math class
316: classes().put(math.get_class()->base()->name(), &math);
1.117 paf 317: }
1.150 parser 318:
1.64 paf 319: /**
320: load MAIN class, execute @main.
321: MAIN class consists of all the auto.p files we'd manage to find
322: plus
323: the file user requested us to process
324: all located classes become children of one another,
325: composing class we name 'MAIN'
326: */
1.153 parser 327: void Request::core(
328: const char *root_config_filespec, bool root_config_fail_on_read_problem,
329: const char *site_config_filespec, bool site_config_fail_on_read_problem,
1.62 paf 330: bool header_only) {
1.121 paf 331: //_asm { int 3 }
1.41 paf 332: bool need_rethrow=false; Exception rethrow_me;
1.3 paf 333: TRY {
1.29 paf 334: char *auto_filespec=(char *)malloc(MAX_STRING);
335:
1.153 parser 336: // loading root config
337: if(root_config_filespec) {
1.77 paf 338: String& filespec=*NEW String(pool());
1.153 parser 339: filespec.APPEND_CLEAN(root_config_filespec, 0, "root_config", 0);
1.29 paf 340: main_class=use_file(
1.148 parser 341: filespec,
1.153 parser 342: true/*ignore class_path*/, root_config_fail_on_read_problem,
1.37 paf 343: main_class_name, main_class);
1.29 paf 344: }
345:
1.124 paf 346: // configure root options
1.72 paf 347: // until someone with less privileges have overriden them
1.129 paf 348: OP.configure_admin(*this);
1.124 paf 349: methoded_array->configure_admin(*this);
1.72 paf 350:
1.153 parser 351: // loading site config
352: if(site_config_filespec) {
1.77 paf 353: String& filespec=*NEW String(pool());
1.153 parser 354: filespec.APPEND_CLEAN(site_config_filespec, 0, "site_config", 0);
1.37 paf 355: main_class=use_file(
1.148 parser 356: filespec,
1.153 parser 357: true/*ignore class_path*/, site_config_fail_on_read_problem,
1.37 paf 358: main_class_name, main_class);
1.29 paf 359: }
1.8 paf 360:
1.72 paf 361: // loading auto.p files from document_root/..
362: // to the one beside requested file.
363: // all assigned bases from upper dir
364: {
1.115 paf 365: const char *after=info.path_translated;
366: size_t drlen=strlen(info.document_root);
367: if(memcmp(after, info.document_root, drlen)==0) {
368: after+=drlen;
369: if(after[-1]=='/')
370: --after;
371: }
372:
1.152 parser 373: int step=0;
1.115 paf 374: while(const char *before=strchr(after, '/')) {
1.152 parser 375: String& sfile_spec=*NEW String(pool());
1.115 paf 376: if(after!=info.path_translated) {
1.152 parser 377: sfile_spec.APPEND_CLEAN(
378: info.path_translated, before-info.path_translated,
379: "path-translated-scanned", step++);
380: sfile_spec << "/" AUTO_FILE_NAME;
381:
382: main_class=use_file(sfile_spec,
383: true/*ignore class_path*/, false/*ignore read problem*/,
384: main_class_name, main_class);
1.115 paf 385: }
386: after=before+1;
1.72 paf 387: }
388: }
1.34 paf 389:
1.125 paf 390: // compile requested file
1.77 paf 391: String& spath_translated=*NEW String(pool());
1.136 parser 392: spath_translated.APPEND_TAINTED(info.path_translated, 0, "user-request", 0);
1.148 parser 393: main_class=use_file(spath_translated,
394: true/*ignore class_path*/, true/*don't ignore read problem*/,
1.72 paf 395: main_class_name, main_class);
1.7 paf 396:
1.124 paf 397: // configure not-root=user options
1.129 paf 398: OP.configure_user(*this);
1.124 paf 399: methoded_array->configure_user(*this);
400:
1.85 paf 401: // $MAIN:DEFAULTS
1.78 paf 402: Value *defaults=main_class->get_element(*defaults_name);
1.75 paf 403: // value must be allocated on request's pool for that pool used on
404: // meaning constructing @see attributed_meaning_to_string
1.80 paf 405: default_content_type=defaults?defaults->get_element(*content_type_name):0;
1.155 parser 406: #ifdef XML
407: // record default charset
1.154 parser 408: if(default_content_type)
409: if(Hash *hash=default_content_type->get_hash())
410: if(Value *vcharset=(Value *)hash->get(*charset_name))
411: pool().set_charset(vcharset->as_string());
1.155 parser 412: #endif
1.154 parser 413:
1.117 paf 414: if(Value *element=main_class->get_element(*user_html_name))
1.87 paf 415: if(Table *table=element->get_table())
1.147 parser 416: pool().set_tag(NEW Dictionary(*table));
1.85 paf 417:
418: // $MAIN:MIME-TYPES
419: if(Value *element=main_class->get_element(*mime_types_name))
420: if(Table *table=element->get_table())
421: mime_types=table;
1.96 paf 422:
1.158 parser 423: if(Value *vctype=main_class->get_element(*ctype_name)) {
424: if(Hash *ctype=vctype->get_hash())
425: ctype->for_each(load_ctype_for_charset, &CTYPE);
426: else
427: THROW(0, 0,
428: &vctype->name(),
429: "must be hash");
430: }
1.102 paf 431:
1.124 paf 432: // filling form fields
1.153 parser 433: form.fill_fields_and_tables(*this);
1.102 paf 434:
1.124 paf 435: // filling cookies
436: cookie.fill_fields(*this);
1.25 paf 437:
438: // execute @main[]
1.143 parser 439: const String *body_string=execute_virtual_method(
440: *main_class, *main_method_name);
1.41 paf 441: if(!body_string)
1.25 paf 442: THROW(0,0,
1.145 parser 443: 0,
444: "'"MAIN_METHOD_NAME"' method not found");
1.79 paf 445:
1.91 paf 446: VString body_vstring_before_post_process(*body_string);
447: VString *body_vstring_after_post_process=&body_vstring_before_post_process;
448:
1.119 paf 449: // @postprocess
1.91 paf 450: if(Value *value=main_class->get_element(*post_process_method_name))
451: if(Junction *junction=value->get_junction())
452: if(const Method *method=junction->method) {
453: // preparing to pass parameters to
1.119 paf 454: // @postprocess[data]
1.146 parser 455: VMethodFrame frame(pool(), value->name(), *junction);
1.91 paf 456: frame.set_self(*main_class);
457:
458: frame.store_param(method->name,
459: &body_vstring_before_post_process);
460: body_vstring_after_post_process=
461: NEW VString(*execute_method(frame, *method));
462: }
1.90 paf 463:
1.144 parser 464: bool origins_mode=main_class->get_element(*origins_mode_name)!=0;
465:
466: const VFile *body_file=body_vstring_after_post_process->as_vfile(
467: String::UL_UNSPECIFIED, origins_mode);
1.41 paf 468:
1.45 paf 469: // extract response body
470: Value *body_value=static_cast<Value *>(
471: response.fields().get(*body_name));
1.119 paf 472: if(body_value) // there is some $response.body
1.90 paf 473: body_file=body_value->as_vfile();
1.144 parser 474: else if(origins_mode)
475: response.fields().put(*content_type_name,
476: NEW VString(*NEW String(pool(), ORIGINS_CONTENT_TYPE)));
1.45 paf 477:
478: // OK. write out the result
1.90 paf 479: output_result(*body_file, header_only);
1.3 paf 480: }
1.76 paf 481: CATCH(e) { // request handling problem
482: // we're returning not result, but error explanation
1.30 paf 483: TRY {
1.76 paf 484: // log the beast
485: const String *problem_source=e.problem_source();
1.114 paf 486: if(problem_source && problem_source->size())
1.76 paf 487: SAPI::log(pool(),
488: #ifndef NO_STRING_ORIGIN
489: "%s(%d): "
490: #endif
491: "'%s' %s [%s %s]",
492: #ifndef NO_STRING_ORIGIN
493: problem_source->origin().file?problem_source->origin().file:"global",
494: problem_source->origin().line,
495: #endif
1.99 paf 496: problem_source->cstr(String::UL_AS_IS),
1.76 paf 497: e.comment(),
1.99 paf 498: e.type()?e.type()->cstr(String::UL_AS_IS):"-",
499: e.code()?e.code()->cstr(String::UL_AS_IS):"-"
1.76 paf 500: );
501: else
502: SAPI::log(pool(),
503: "%s [%s %s]",
504: e.comment(),
1.99 paf 505: e.type()?e.type()->cstr(String::UL_AS_IS):"-",
506: e.code()?e.code()->cstr(String::UL_AS_IS):"-"
1.76 paf 507: );
1.43 paf 508:
509: // reset language to default
510: flang=fdefault_lang;
1.135 parser 511: if(flang==String::UL_USER_HTML)
1.137 parser 512: flang=String::UL_HTML; // no _ & Co conversions in @exception[params]
1.43 paf 513:
514: // reset response
515: response.fields().clear();
516:
517: // this is what we'd return in $response:body
1.41 paf 518: const String *body_string=0;
1.43 paf 519:
1.30 paf 520: if(main_class) { // we've managed to end up with some main_class
521: // maybe we'd be lucky enough as to report an error
522: // in a gracefull way...
523: if(Value *value=main_class->get_element(*exception_method_name))
524: if(Junction *junction=value->get_junction())
525: if(const Method *method=junction->method) {
526: // preparing to pass parameters to
527: // @exception[origin;source;comment;type;code]
1.146 parser 528: VMethodFrame frame(pool(), value->name(), *junction);
1.38 paf 529: frame.set_self(*main_class);
1.30 paf 530:
531: const String *problem_source=e.problem_source();
532: // origin
1.38 paf 533: Value *origin_value=0;
1.30 paf 534: #ifndef NO_STRING_ORIGIN
1.114 paf 535: if(problem_source && problem_source->size()) {
1.38 paf 536: const Origin& origin=problem_source->origin();
537: if(origin.file) {
538: char *buf=(char *)malloc(MAX_STRING);
1.106 paf 539: size_t buf_size=snprintf(buf, MAX_STRING, "%s(%d):",
1.38 paf 540: origin.file, 1+origin.line);
1.44 paf 541: String *origin_file_line=NEW String(pool(),
1.106 paf 542: buf, buf_size, true);
1.38 paf 543: origin_value=NEW VString(*origin_file_line);
544: }
1.30 paf 545: }
546: #endif
1.91 paf 547: frame.store_param(method->name,
1.138 parser 548: origin_value?origin_value:NEW VVoid(pool()));
1.28 paf 549:
1.30 paf 550: // source
1.38 paf 551: Value *source_value=0;
1.114 paf 552: if(problem_source && problem_source->size()) {
1.47 paf 553: String& problem_source_copy=*NEW String(pool());
554: problem_source_copy.append(*problem_source,
555: flang, true);
1.43 paf 556: source_value=NEW VString(problem_source_copy);
557: }
1.91 paf 558: frame.store_param(method->name,
1.138 parser 559: source_value?source_value:NEW VVoid(pool()));
1.30 paf 560:
561: // comment
1.44 paf 562: String *comment_value=NEW String(pool(),
1.106 paf 563: e.comment(), 0, true);
1.91 paf 564: frame.store_param(method->name,
1.30 paf 565: NEW VString(*comment_value));
566:
567: // type
568: Value *type_value;
1.43 paf 569: if(e.type()) {
1.47 paf 570: String& type_copy=*NEW String(pool());
571: type_value=NEW VString(type_copy.append(*e.type(),
572: flang, true));
1.43 paf 573: } else
1.138 parser 574: type_value=NEW VVoid(pool());
1.91 paf 575: frame.store_param(method->name, type_value);
1.30 paf 576:
577: // code
578: Value *code_value;
1.43 paf 579: if(e.code()) {
1.47 paf 580: String& code_copy=*NEW String(pool());
581: code_value=NEW VString(code_copy.append(*e.code(),
582: flang, true));
1.43 paf 583: } else
1.138 parser 584: code_value=NEW VVoid(pool());
1.91 paf 585: frame.store_param(method->name, code_value);
1.30 paf 586:
1.43 paf 587: // future $response:body=
588: // execute ^exception[origin;source;comment;type;code]
589: body_string=execute_method(frame, *method);
1.30 paf 590: }
591: }
592:
1.41 paf 593: if(!body_string) { // couldn't report an error beautifully?
594: // doing that ugly
595:
596: // make up result: $origin $source $comment $type $code
597: char *buf=(char *)malloc(MAX_STRING);
1.30 paf 598: size_t printed=0;
599: const String *problem_source=e.problem_source();
600: if(problem_source) {
1.16 paf 601: #ifndef NO_STRING_ORIGIN
1.30 paf 602: const Origin& origin=problem_source->origin();
603: if(origin.file)
1.41 paf 604: printed+=snprintf(buf+printed, MAX_STRING-printed, "%s(%d): ",
1.30 paf 605: origin.file, 1+origin.line);
1.28 paf 606: #endif
1.41 paf 607: printed+=snprintf(buf+printed, MAX_STRING-printed, "'%s' ",
1.99 paf 608: problem_source->cstr(String::UL_AS_IS));
1.30 paf 609: }
1.41 paf 610: printed+=snprintf(buf+printed, MAX_STRING-printed, "%s",
1.30 paf 611: e.comment());
612: const String *type=e.type();
613: if(type) {
1.41 paf 614: printed+=snprintf(buf+printed, MAX_STRING-printed, " type: %s",
1.99 paf 615: type->cstr(String::UL_AS_IS));
1.30 paf 616: const String *code=e.code();
617: if(code)
1.41 paf 618: printed+=snprintf(buf+printed, MAX_STRING-printed, ", code: %s",
1.99 paf 619: code->cstr(String::UL_AS_IS));
1.30 paf 620: }
1.43 paf 621:
622: // future $response:content-type
1.49 paf 623: response.fields().put(*content_type_name,
1.82 paf 624: NEW VString(*NEW String(pool(), UNHANDLED_EXCEPTION_CONTENT_TYPE)));
1.43 paf 625: // future $response:body
1.44 paf 626: body_string=NEW String(pool(), buf);
1.30 paf 627: }
1.41 paf 628:
1.144 parser 629: VString body_vstring(*body_string);
1.90 paf 630: const VFile *body_file=body_vstring.as_vfile();
631:
1.45 paf 632: // ERROR. write it out
1.90 paf 633: output_result(*body_file, header_only);
1.3 paf 634: }
1.30 paf 635: CATCH(e) {
1.41 paf 636: // exception in request exception handler
637: // remember to rethrow it
638: rethrow_me=e; need_rethrow=true;
1.1 paf 639: }
1.30 paf 640: END_CATCH
1.1 paf 641: }
1.41 paf 642: END_CATCH // do not use pool() after this point - no exception handler set
643: // any throw() would try to use zero exception() pointer
644:
1.91 paf 645: if(need_rethrow) // were there an exception for us to rethrow?
1.62 paf 646: THROW(rethrow_me.type(), rethrow_me.code(),
1.41 paf 647: rethrow_me.problem_source(),
648: rethrow_me.comment());
1.1 paf 649: }
650:
1.148 parser 651: VStateless_class *Request::use_file(const String& file_name,
652: bool ignore_class_path, bool fail_on_read_problem,
1.26 paf 653: const String *name,
654: VStateless_class *base_class) {
1.73 paf 655: // cyclic dependence check
1.148 parser 656: if(used_files.get(file_name))
1.73 paf 657: return base_class;
1.148 parser 658: used_files.put(file_name, (Hash::Val *)true);
1.73 paf 659:
1.148 parser 660: const String *file_spec;
1.153 parser 661: if(ignore_class_path) // ignore_class_path?
1.148 parser 662: file_spec=&file_name;
1.153 parser 663: else if(file_name.first_char()=='/') //absolute path, no need to scan MAIN:CLASS_PATH?
664: file_spec=&absolute(file_name);
665: else {
666: file_spec=0;
667: if(main_class)
668: if(Value *element=main_class->get_element(*class_path_name)) {
669: if(element->is_string()) {
670: file_spec=file_readable(element->as_string(), file_name); // found at class_path?
671: } else if(Table *table=element->get_table()) {
672: int size=table->size();
673: for(int i=size; i--; ) {
674: const String& path=*static_cast<Array *>(table->get(i))->get_string(0);
675: if(file_spec=file_readable(path, file_name))
676: break; // found along class_path
1.148 parser 677: }
1.153 parser 678: } else
679: THROW(0, 0,
680: &element->name(),
681: "must be string or table");
682: if(!file_spec)
683: THROW(0, 0,
684: &file_name,
685: "not found along " MAIN_CLASS_NAME ":" CLASS_PATH_NAME);
686: }
687: if(!file_spec)
688: THROW(0, 0,
689: &file_name,
690: "usage failed - no " MAIN_CLASS_NAME ":" CLASS_PATH_NAME " were specified");
1.148 parser 691: }
1.73 paf 692:
1.148 parser 693: char *source=file_read_text(pool(), *file_spec, fail_on_read_problem);
1.3 paf 694: if(!source)
1.12 paf 695: return base_class;
1.3 paf 696:
1.148 parser 697: return use_buf(source, file_spec->cstr(), 0/*new class*/, name, base_class);
1.16 paf 698: }
699:
1.67 paf 700: VStateless_class *Request::use_buf(const char *source, const char *file,
1.26 paf 701: VStateless_class *aclass, const String *name,
702: VStateless_class *base_class) {
1.5 paf 703: // compile loaded class
1.26 paf 704: VStateless_class& cclass=COMPILE(source, aclass, name, base_class, file);
1.1 paf 705:
1.4 paf 706: // locate and execute possible @auto[] static method
1.143 parser 707: execute_nonvirtual_method(cclass, *auto_method_name, false /*no result needed*/);
1.16 paf 708: return &cclass;
1.19 paf 709: }
710:
1.77 paf 711: const String& Request::relative(const char *apath, const String& relative_name) {
712: int lpath_buf_size=strlen(apath)+1;
713: char *lpath=(char *)malloc(lpath_buf_size);
714: memcpy(lpath, apath, lpath_buf_size);
1.120 paf 715: if(!rsplit(lpath, '/'))
716: strcpy(lpath, ".");
1.77 paf 717: String& result=*NEW String(pool(), lpath);
1.104 paf 718: result << "/" << relative_name;
1.19 paf 719: return result;
720: }
721:
1.77 paf 722: const String& Request::absolute(const String& relative_name) {
723: char *relative_name_cstr=relative_name.cstr();
724: if(relative_name_cstr[0]=='/') {
725: String& result=*NEW String(pool(), info.document_root);
1.104 paf 726: result << relative_name;
1.19 paf 727: return result;
728: } else
1.77 paf 729: return relative(info.path_translated, relative_name);
1.1 paf 730: }
1.45 paf 731:
1.101 paf 732: static void add_header_attribute(const Hash::Key& aattribute, Hash::Val *ameaning,
733: void *info) {
734: String *attribute_to_exclude=static_cast<String *>(info);
735: if(aattribute==*attribute_to_exclude)
736: return;
737:
738: Value& lmeaning=*static_cast<Value *>(ameaning);
739: Pool& pool=lmeaning.pool();
740:
741: SAPI::add_header_attribute(pool,
1.116 paf 742: aattribute.cstr(String::UL_AS_IS),
1.101 paf 743: attributed_meaning_to_string(lmeaning, String::UL_HTTP_HEADER).cstr());
744: }
1.90 paf 745: void Request::output_result(const VFile& body_file, bool header_only) {
1.51 paf 746: // header: cookies
747: cookie.output_result();
748:
1.90 paf 749: // set content-type
750: if(String *body_file_content_type=static_cast<String *>(
751: body_file.fields().get(*vfile_mime_type_name))) {
752: // body file content type
753: response.fields().put(*content_type_name, body_file_content_type);
754: } else {
755: // default content type
756: response.fields().put_dont_replace(*content_type_name,
757: default_content_type?default_content_type
758: :NEW VString(*NEW String(pool(), DEFAULT_CONTENT_TYPE)));
1.92 paf 759: }
760:
761: // content-disposition
1.111 paf 762: if(VString *vfile_name=static_cast<VString *>(body_file.fields().get(*name_name)))
763: if(vfile_name->string()!=NONAME_DAT) {
764: VHash& vhash=*NEW VHash(pool());
765: vhash.hash().put(*content_disposition_filename_name, vfile_name);
766: response.fields().put(*content_disposition_name, &vhash);
767: }
1.49 paf 768:
1.62 paf 769: // prepare header: $response:fields without :body
1.73 paf 770: response.fields().for_each(add_header_attribute, /*excluding*/ body_name);
1.50 paf 771:
1.62 paf 772: // prepare...
1.90 paf 773: const void *body=body_file.value_ptr();
774: size_t content_length=body_file.value_size();
1.50 paf 775:
1.62 paf 776: // prepare header: content-length
1.65 paf 777: if(content_length) { // useful for redirecting [header "location: http://..."]
778: char content_length_cstr[MAX_NUMBER];
1.108 paf 779: snprintf(content_length_cstr, MAX_NUMBER, "%u", content_length);
1.69 paf 780: SAPI::add_header_attribute(pool(), "content-length", content_length_cstr);
1.65 paf 781: }
1.62 paf 782:
783: // send header
1.69 paf 784: SAPI::send_header(pool());
1.71 paf 785:
1.62 paf 786: // send body
787: if(!header_only)
1.69 paf 788: SAPI::send_body(pool(), body, content_length);
1.50 paf 789: }
1.104 paf 790:
791: const String& Request::mime_type_of(const char *user_file_name_cstr) {
792: if(mime_types)
793: if(const char *cext=strrchr(user_file_name_cstr, '.')) {
794: String sext(pool(), ++cext);
795: if(mime_types->locate(0, sext))
796: if(const String *result=mime_types->item(1))
797: return *result;
798: else
799: THROW(0, 0,
800: mime_types->origin_string(),
801: "MIME-TYPE table column elements must not be empty");
802: }
803: return *NEW String(pool(), "application/octet-stream");
1.158 parser 804: }
805:
806: unsigned char *Request::pcre_tables() {
1.159 ! parser 807: if(unsigned char *result=(unsigned char *)CTYPE.get(pool().get_charset()))
! 808: return result;
1.158 parser 809:
810: return pcre_default_tables;
1.133 parser 811: }
E-mail: