Annotation of parser3/src/include/pa_request.h, revision 1.206
1.61 paf 1: /** @file
1.62 paf 2: Parser: request class decl.
3:
1.190 misha 4: Copyright (c) 2001-2009 ArtLebedev Group (http://www.artlebedev.com)
1.121 paf 5: Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
1.1 paf 6: */
7:
8: #ifndef PA_REQUEST_H
9: #define PA_REQUEST_H
1.141 paf 10:
1.206 ! misha 11: static const char * const IDENT_REQUEST_H="$Date: 2010-09-04 23:33:21 $";
1.1 paf 12:
1.168 paf 13: #include "pa_pool.h"
1.5 paf 14: #include "pa_hash.h"
1.7 paf 15: #include "pa_wcontext.h"
1.6 paf 16: #include "pa_value.h"
1.7 paf 17: #include "pa_stack.h"
1.162 paf 18: #include "pa_request_info.h"
19: #include "pa_request_charsets.h"
20: #include "pa_sapi.h"
1.183 misha 21: #include "pa_vconsole.h"
1.44 paf 22:
1.112 paf 23: #ifdef RESOURCES_DEBUG
24: #include <sys/resource.h>
25: #endif
26:
1.128 paf 27: // consts
28:
1.161 paf 29: const uint ANTI_ENDLESS_EXECUTE_RECOURSION=1000;
1.206 ! misha 30: const uint ANTI_ENDLESS_JSON_STRING_RECOURSION=100;
1.162 paf 31: const size_t pseudo_file_no__process=1;
1.128 paf 32:
1.162 paf 33: // forwards
1.4 paf 34:
1.39 paf 35: class Temp_lang;
1.84 paf 36: class Methoded;
1.116 paf 37: class VMethodFrame;
1.162 paf 38: class VMail;
39: class VForm;
40: class VResponse;
41: class VCookie;
42: class VStateless_class;
1.1 paf 43:
1.61 paf 44: /// Main workhorse.
1.162 paf 45: class Request: public PA_Object {
1.107 paf 46: friend class Temp_lang;
1.117 paf 47: friend class Temp_connection;
1.148 paf 48: friend class Request_context_saver;
1.155 paf 49: friend class Temp_request_self;
1.162 paf 50: friend class Exception_trace;
51:
1.1 paf 52: public:
1.162 paf 53: class Trace {
54: const String* fname;
55: Operation::Origin forigin;
56: public:
57: Trace(): fname(0) {}
58: void clear() { fname=0; }
59: operator bool() const { return fname!=0; }
60:
61: Trace(const String* aname, const Operation::Origin aorigin):
62: fname(aname), forigin(aorigin) {}
63:
64: const String* name() const { return fname; }
65: const Operation::Origin origin() const { return forigin; }
66: };
67:
1.181 paf 68: enum Skip {
69: SKIP_NOTHING,
70: SKIP_BREAK,
71: SKIP_CONTINUE
72: };
73:
1.168 paf 74: private:
75: Pool fpool;
76: public:
77: Pool& pool() { return fpool; }
1.162 paf 78:
79: private:
80: union StackItem {
81: Value* fvalue;
82: ArrayOperation* fops;
83: VMethodFrame* fmethod_frame;
84: public:
85: Value& value() const { return *fvalue; }
86: const String& string() const {
1.167 paf 87: return fvalue->as_string();
1.162 paf 88: }
89: ArrayOperation& ops() const { return *fops; }
90: VMethodFrame& method_frame() const { return *fmethod_frame; }
91:
92: /// needed to fill unused Array entries
93: StackItem() {}
94: StackItem(Value& avalue): fvalue(&avalue) {}
95: StackItem(ArrayOperation& aops): fops(&aops) {}
96: StackItem(VMethodFrame& amethod_frame): fmethod_frame(&amethod_frame) {}
97: };
98:
99: class Exception_trace: public Stack<Trace> {
100: size_t fbottom;
101: public:
102: Exception_trace(): fbottom(0) {}
103:
104: size_t bottom_index() { return fbottom; }
1.165 paf 105: void set_bottom_index(size_t abottom) { fbottom=abottom; }
1.162 paf 106: element_type bottom_value() { return get(bottom_index()); }
107:
108: void clear() {
1.191 misha 109: fused=fbottom=0;
1.162 paf 110: }
111:
112: bool is_empty() {
1.191 misha 113: return fused==fbottom;
1.162 paf 114: }
115:
116: const element_type extract_origin(const String*& problem_source);
117: };
118:
119: ///@{ core data
120:
121: /// classes
1.195 misha 122: HashString<Value*> fclasses;
1.162 paf 123:
124: /// already used files to avoid cyclic uses
1.193 misha 125: HashString<bool> used_files;
1.200 misha 126: HashString<bool> searched_along_class_path;
1.162 paf 127: /// list of all used files, Operation::file_no = index to it
1.163 paf 128: Array<String::Body> file_list;
1.162 paf 129:
130: /** endless execute(execute(... preventing counter
131: @see ANTI_ENDLESS_EXECUTE_RECOURSION
132: */
133: uint anti_endless_execute_recoursion;
134:
1.206 ! misha 135: uint anti_endless_json_string_recoursion;
! 136:
1.162 paf 137: ///@}
138:
139: /// execution stack
140: Stack<StackItem> stack;
141:
142: /// exception stack trace
143: Exception_trace exception_trace;
144: public:
145:
146: //@{ request processing status
147: /// contexts
148: VMethodFrame* method_frame;
149: Value* rcontext;
150: WContext* wcontext;
151: /// current language
152: String::Language flang;
153: /// current connection
154: SQL_Connection* fconnection;
155: //@}
156: /// interrupted flag, raised on signals [SIGPIPE]
157: bool finterrupted;
1.181 paf 158: Skip fskip;
1.196 misha 159: int fin_cycle;
1.162 paf 160:
161: public:
1.175 paf 162: uint register_file(String::Body file_spec);
1.162 paf 163:
164: struct Exception_details {
165: const Trace trace;
166: const String* problem_source;
167: VHash& vhash;
168:
169: Exception_details(
170: const Trace atrace,
171: const String* aproblem_source,
1.166 paf 172: VHash& avhash): trace(atrace), problem_source(aproblem_source), vhash(avhash) {}
1.162 paf 173: };
174: Exception_details get_details(const Exception& e);
1.176 paf 175: const char* get_exception_cstr(const Exception& e, Exception_details& details);
1.162 paf 176:
177: /// @see Stack::wipe_unused
178: void wipe_unused_execution_stack() {
179: stack.wipe_unused();
180: }
1.112 paf 181:
182: #ifdef RESOURCES_DEBUG
183: /// measures
184: double sql_connect_time;
185: double sql_request_time;
186: #endif
1.61 paf 187:
1.162 paf 188: Request(SAPI_Info& asapi_info, Request_info& arequest_info,
189: String::Language adefault_lang, ///< all tainted data default untainting lang
1.110 paf 190: bool status_allowed ///< status class allowed
1.50 paf 191: );
1.118 paf 192: ~Request();
1.1 paf 193:
1.61 paf 194: /// global classes
1.195 misha 195: HashString<Value*>& classes() { return fclasses; }
1.197 misha 196: Value* get_class(const String& name);
1.6 paf 197:
1.65 paf 198: /**
199: core request processing
200:
201: BEWARE: may throw exception to you: catch it!
202: */
203: void core(
1.162 paf 204: const char* config_filespec, ///< system config filespec
1.138 paf 205: bool config_fail_on_read_problem, ///< fail if system config file not found
1.65 paf 206: bool header_only);
1.17 paf 207:
1.61 paf 208: /// executes ops
1.162 paf 209: void execute(ArrayOperation& ops); // execute.C
1.192 misha 210: void op_call(VMethodFrame &frame);
211: void op_call_write(VMethodFrame &frame);
1.202 moko 212: Value& construct(Value &class_value, const Method &method);
213:
1.127 paf 214: /// execute ops with anti-recoursion check
1.162 paf 215: void recoursion_checked_execute(/*const String& name, */ArrayOperation& ops) {
1.128 paf 216: // anti_endless_execute_recoursion
217: if(++anti_endless_execute_recoursion==ANTI_ENDLESS_EXECUTE_RECOURSION) {
218: anti_endless_execute_recoursion=0; // give @exception a chance
1.184 misha 219: throw Exception(PARSER_RUNTIME,
1.162 paf 220: 0, //&name,
1.128 paf 221: "call canceled - endless recursion detected");
222: }
1.147 paf 223: execute(ops); // execute it
1.128 paf 224: anti_endless_execute_recoursion--;
225: }
1.40 paf 226:
1.206 ! misha 227: void json_string_recoursion_go_down(){
! 228: if(++anti_endless_json_string_recoursion==ANTI_ENDLESS_JSON_STRING_RECOURSION){
! 229: anti_endless_json_string_recoursion=0;
! 230: throw Exception(PARSER_RUNTIME,
! 231: 0,
! 232: "call canceled - endless json recursion detected");
! 233: }
! 234: }
! 235:
! 236: void json_string_recoursion_go_up(){
! 237: if(anti_endless_json_string_recoursion)
! 238: anti_endless_json_string_recoursion--;
! 239: }
! 240:
1.199 misha 241: ///
242: void use_file_directly(VStateless_class& aclass,
243: const String& file_spec,
244: bool fail_on_read_problem=true,
1.201 misha 245: bool fail_on_file_absence=true);
1.199 misha 246:
1.64 paf 247: /// compiles the file, maybe forcing it's class @a name and @a base_class.
1.162 paf 248: void use_file(VStateless_class& aclass,
1.199 misha 249: const String& file_name,
1.201 misha 250: const String* use_filespec);
1.199 misha 251:
1.64 paf 252: /// compiles a @a source buffer
1.162 paf 253: void use_buf(VStateless_class& aclass,
254: const char* source,
255: const String* main_alias,
1.175 paf 256: uint file_no,
1.201 misha 257: int line_no_offset=0);
1.28 paf 258:
1.129 paf 259: /// processes any code-junction there may be inside of @a value
1.203 moko 260: StringOrValue process_getter(Junction& junction); // execute.C
1.131 paf 261: StringOrValue process(Value& input_value, bool intercept_string=true); // execute.C
1.192 misha 262: void process_write(Value& input_value); // execute.C
1.129 paf 263: //@{ convinient helpers
264: const String& process_to_string(Value& input_value) {
265: return process(input_value, true/*intercept_string*/).as_string();
266: }
267: Value& process_to_value(Value& input_value, bool intercept_string=true) {
268: return process(input_value, intercept_string).as_value();
1.126 paf 269: }
270: //@}
1.201 misha 271: const String* get_method_filename(const Method* method); // execute.C
1.199 misha 272: const String* get_used_filename(uint file_no);
1.126 paf 273:
1.131 paf 274: #define DEFINE_DUAL(modification) \
275: void write_##modification##_lang(StringOrValue dual) { \
1.162 paf 276: if(const String* string=dual.get_string()) \
1.131 paf 277: write_##modification##_lang(*string); \
278: else \
279: write_##modification##_lang(*dual.get_value()); \
280: }
281:
1.61 paf 282: /// appending, sure of clean string inside
1.65 paf 283: void write_no_lang(const String& astring) {
1.111 paf 284: wcontext->write(astring,
1.162 paf 285: (String::Language)(String::L_CLEAN | flang&String::L_OPTIMIZE_BIT));
1.49 paf 286: }
1.131 paf 287: /// appending sure value, that would be converted to clean string
288: void write_no_lang(Value& avalue) {
289: if(wcontext->get_in_expression())
290: wcontext->write(avalue);
291: else
292: wcontext->write(avalue,
1.162 paf 293: (String::Language)(String::L_CLEAN | flang&String::L_OPTIMIZE_BIT));
1.131 paf 294: }
295:
1.61 paf 296: /// appending string, passing language built into string being written
1.65 paf 297: void write_pass_lang(const String& astring) {
1.162 paf 298: wcontext->write(astring, String::L_PASS_APPENDED);
1.59 paf 299: }
1.131 paf 300: /// appending possible string, passing language built into string being written
301: void write_pass_lang(Value& avalue) {
1.162 paf 302: wcontext->write(avalue, String::L_PASS_APPENDED);
1.131 paf 303: }
304: DEFINE_DUAL(pass)
305:
1.61 paf 306: /// appending possible string, assigning untaint language
1.40 paf 307: void write_assign_lang(Value& avalue) {
1.39 paf 308: wcontext->write(avalue, flang);
1.106 parser 309: }
310: /// appending string, assigning untaint language
311: void write_assign_lang(const String& astring) {
312: wcontext->write(astring, flang);
1.22 paf 313: }
1.131 paf 314: DEFINE_DUAL(assign)
1.22 paf 315:
1.64 paf 316: /// returns relative to @a path path to @a file
1.162 paf 317: const String& relative(const char* apath, const String& relative_name);
1.61 paf 318:
1.64 paf 319: /// returns an absolute @a path to relative @a name
1.69 paf 320: const String& absolute(const String& relative_name);
1.42 paf 321:
1.80 paf 322: /// returns the mime type of 'user_file_name_cstr'
1.162 paf 323: const String& mime_type_of(const char* user_file_name_cstr);
1.80 paf 324:
1.117 paf 325: /// returns current SQL connection if any
1.162 paf 326: SQL_Connection* connection(bool fail_on_error=true) {
327: if(fail_on_error && !fconnection)
1.184 misha 328: throw Exception(PARSER_RUNTIME,
1.162 paf 329: 0,
1.117 paf 330: "outside of 'connect' operator");
331:
332: return fconnection;
1.133 paf 333: }
334:
1.162 paf 335: void set_interrupted(bool ainterrupted) { finterrupted=ainterrupted; }
336: bool get_interrupted() { return finterrupted; }
1.158 paf 337:
1.181 paf 338: void set_skip(Skip askip) { fskip=askip; }
339: Skip get_skip() { return fskip; }
340:
1.196 misha 341: void set_in_cycle(int adelta) { fin_cycle+=adelta; }
342: bool get_in_cycle() { return fin_cycle>0; }
343:
1.17 paf 344: public:
1.22 paf 345:
1.61 paf 346: /// info from web server
1.162 paf 347: Request_info& request_info;
348:
349: /// info about ServerAPI
350: SAPI_Info& sapi_info;
351:
352: /// source, client, mail charsets
353: Request_charsets charsets;
1.53 paf 354:
1.154 paf 355: /// 'MAIN' class conglomerat & operators are methods of this class
1.162 paf 356: VStateless_class& main_class;
1.86 paf 357: /// $form:elements
1.162 paf 358: VForm& form;
1.140 paf 359: /// $mail
1.162 paf 360: VMail& mail;
1.86 paf 361: /// $response:elements
1.162 paf 362: VResponse& response;
1.86 paf 363: /// $cookie:elements
1.162 paf 364: VCookie& cookie;
1.183 misha 365: /// $console
366: VConsole& console;
1.70 paf 367:
1.148 paf 368: /// classes configured data
1.193 misha 369: HashString<void*> classes_conf;
1.85 paf 370:
1.148 paf 371: public: // status read methods
1.76 paf 372:
1.148 paf 373: VMethodFrame *get_method_frame() { return method_frame; }
1.162 paf 374: Value& get_self();
375: #define GET_SELF(request, type) (static_cast<type &>(request.get_self()))
376: /* for strange reason call to this:
377: r.get_self<VHash>()
378: refuses to compile
1.87 paf 379:
1.162 paf 380: template<typename T> T& get_self() {
381: return *static_cast<T*>(get_self().get());
382: }
383: */
1.6 paf 384:
1.205 moko 385: /// public for ^reflection:copy[]
386: void put_element(Value& ncontext, const String& name, Value* value);
387:
1.173 paf 388: /// for @main[]
389: const String* execute_virtual_method(Value& aself, const String& method_name);
390:
1.204 moko 391: /// executes parser method, use op_call(frame) to execute native method
392: void execute_method(VMethodFrame& aframe);
393:
1.173 paf 394: //{ for @conf[filespec] and @auto[filespec] and parser://method/call
395: const String* execute_method(Value& aself,
1.190 misha 396: const Method& method, Value* optional_param,
1.173 paf 397: bool do_return_string);
398: struct Execute_nonvirtual_method_result {
399: const String* string;
400: Method* method;
401: Execute_nonvirtual_method_result(): string(0), method(0) {}
402: };
403: Execute_nonvirtual_method_result execute_nonvirtual_method(VStateless_class& aclass,
1.185 misha 404: const String& method_name,
405: VString* optional_param,
1.173 paf 406: bool do_return_string);
407: //}
408:
1.162 paf 409: #ifdef XML
410: public: // charset helpers
1.67 paf 411:
1.162 paf 412: /// @see Charset::transcode
1.180 paf 413: xmlChar* transcode(const String& s);
1.162 paf 414: /// @see Charset::transcode
1.180 paf 415: xmlChar* transcode(const String::Body s);
1.162 paf 416: /// @see Charset::transcode
1.180 paf 417: const String& transcode(const xmlChar* s);
1.89 parser 418:
1.162 paf 419: #endif
1.136 paf 420:
421: private:
422:
423: /// already executed some @conf method
424: bool configure_admin_done;
425:
1.162 paf 426: void configure_admin(VStateless_class& conf_class);
1.177 paf 427:
428: void configure();
1.99 parser 429:
1.7 paf 430: private: // compile.C
431:
1.189 misha 432: ArrayClass& compile(VStateless_class* aclass,
1.162 paf 433: const char* source, const String* main_alias,
1.175 paf 434: uint file_no,
435: int line_no_offset);
1.7 paf 436:
437: private: // execute.C
1.9 paf 438:
1.191 misha 439: Value& get_element(Value& ncontext, const String& name);
1.22 paf 440:
1.58 paf 441: private: // defaults
442:
1.162 paf 443: const String::Language fdefault_lang;
1.80 paf 444:
445: private: // mime types
446:
447: /// $MAIN:MIME-TYPES
448: Table *mime_types;
1.22 paf 449:
1.39 paf 450: private: // lang manipulation
1.22 paf 451:
1.162 paf 452: String::Language set_lang(String::Language alang) {
453: String::Language result=flang;
1.39 paf 454: flang=alang;
455: return result;
456: }
1.162 paf 457: void restore_lang(String::Language alang) {
1.39 paf 458: flang=alang;
459: }
460:
1.117 paf 461: private: // connection manipulation
462:
1.162 paf 463: SQL_Connection* set_connection(SQL_Connection* aconnection) {
464: SQL_Connection* result=fconnection;
1.117 paf 465: fconnection=aconnection;
466: return result;
467: }
1.162 paf 468: void restore_connection(SQL_Connection* aconnection) {
1.117 paf 469: fconnection=aconnection;
470: }
471:
472: private:
473:
1.162 paf 474: void output_result(VFile* body_file, bool header_only, bool as_attachment);
1.148 paf 475: };
476:
477: /// Auto-object used to save request context across ^try body
478: class Request_context_saver {
479: Request& fr;
480:
481: /// exception stack trace
1.165 paf 482: size_t exception_trace_top;
483: size_t exception_trace_bottom;
1.148 paf 484: /// execution stack
1.162 paf 485: size_t stack;
1.166 paf 486: uint anti_endless_execute_recoursion;
1.206 ! misha 487: uint anti_endless_json_string_recoursion;
1.148 paf 488: /// contexts
1.162 paf 489: VMethodFrame* method_frame;
490: Value* rcontext;
491: WContext* wcontext;
1.148 paf 492: /// current language
1.162 paf 493: String::Language flang;
1.148 paf 494: /// current connection
1.162 paf 495: SQL_Connection* fconnection;
1.126 paf 496:
1.148 paf 497: public:
498: Request_context_saver(Request& ar) :
1.171 paf 499: fr(ar),
1.165 paf 500: exception_trace_top(ar.exception_trace.top_index()),
501: exception_trace_bottom(ar.exception_trace.bottom_index()),
502: stack(ar.stack.top_index()),
1.166 paf 503: anti_endless_execute_recoursion(ar.anti_endless_execute_recoursion),
1.206 ! misha 504: anti_endless_json_string_recoursion(ar.anti_endless_json_string_recoursion),
1.148 paf 505: method_frame(ar.method_frame),
506: rcontext(ar.rcontext),
507: wcontext(ar.wcontext),
508: flang(ar.flang),
1.171 paf 509: fconnection(ar.fconnection) {}
1.153 paf 510: void restore() {
1.165 paf 511: fr.exception_trace.set_top_index(exception_trace_top);
512: fr.exception_trace.set_bottom_index(exception_trace_bottom);
513: fr.stack.set_top_index(stack);
1.166 paf 514: fr.anti_endless_execute_recoursion=anti_endless_execute_recoursion;
1.206 ! misha 515: fr.anti_endless_json_string_recoursion=anti_endless_json_string_recoursion;
1.157 paf 516: fr.method_frame=method_frame, fr.rcontext=rcontext; fr.wcontext=wcontext;
1.148 paf 517: fr.flang=flang;
518: fr.fconnection=fconnection;
519: }
1.39 paf 520: };
521:
1.61 paf 522: /// Auto-object used for temporary changing Request::flang.
1.39 paf 523: class Temp_lang {
524: Request& frequest;
1.162 paf 525: String::Language saved_lang;
1.39 paf 526: public:
1.162 paf 527: Temp_lang(Request& arequest, String::Language alang) :
1.39 paf 528: frequest(arequest),
529: saved_lang(arequest.set_lang(alang)) {
530: }
531: ~Temp_lang() {
532: frequest.restore_lang(saved_lang);
1.117 paf 533: }
534: };
535:
536: /// Auto-object used for temporary changing Request::fconnection.
537: class Temp_connection {
538: Request& frequest;
1.162 paf 539: SQL_Connection* saved_connection;
1.117 paf 540: public:
1.162 paf 541: Temp_connection(Request& arequest, SQL_Connection* aconnection) :
1.117 paf 542: frequest(arequest),
543: saved_connection(arequest.set_connection(aconnection)) {
544: }
545: ~Temp_connection() {
546: frequest.restore_connection(saved_connection);
1.39 paf 547: }
1.91 parser 548: };
549:
1.196 misha 550: /// Auto-object used for break out of cycle check
551: class InCycle {
552: Request& frequest;
553: public:
554: InCycle(Request& arequest) : frequest(arequest) {
555: frequest.set_in_cycle(1);
556: }
557: ~InCycle() {
558: frequest.set_in_cycle(-1);
559: }
560: };
1.91 parser 561:
1.162 paf 562: // defines for externs
1.91 parser 563:
1.170 paf 564: #define EXCEPTION_HANDLED_PART_NAME "handled"
565:
1.162 paf 566:
567: // externs
568:
569: extern const String main_method_name;
570: extern const String auto_method_name;
571: extern const String body_name;
1.186 misha 572:
1.162 paf 573: extern const String exception_type_part_name;
574: extern const String exception_source_part_name;
575: extern const String exception_comment_part_name;
576: extern const String exception_handled_part_name;
1.91 parser 577:
1.162 paf 578: // defines for statics
1.91 parser 579:
1.162 paf 580: #define MAIN_CLASS_NAME "MAIN"
581: #define AUTO_FILE_NAME "auto.p"
1.1 paf 582:
583: #endif
E-mail: