Annotation of parser3/src/include/pa_request.h, revision 1.210
1.61 paf 1: /** @file
1.62 paf 2: Parser: request class decl.
3:
1.210 ! moko 4: Copyright (c) 2001-2012 Art. Lebedev Studio (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.210 ! moko 11: #define IDENT_PA_REQUEST_H "$Id: 2011-11-23 11:41:07 $"
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,
1.208 moko 189: String::Language adefault_lang ///< all tainted data default untainting lang
1.50 paf 190: );
1.118 paf 191: ~Request();
1.1 paf 192:
1.61 paf 193: /// global classes
1.195 misha 194: HashString<Value*>& classes() { return fclasses; }
1.197 misha 195: Value* get_class(const String& name);
1.6 paf 196:
1.65 paf 197: /**
198: core request processing
199:
200: BEWARE: may throw exception to you: catch it!
201: */
202: void core(
1.162 paf 203: const char* config_filespec, ///< system config filespec
1.138 paf 204: bool config_fail_on_read_problem, ///< fail if system config file not found
1.65 paf 205: bool header_only);
1.17 paf 206:
1.61 paf 207: /// executes ops
1.162 paf 208: void execute(ArrayOperation& ops); // execute.C
1.192 misha 209: void op_call(VMethodFrame &frame);
210: void op_call_write(VMethodFrame &frame);
1.202 moko 211: Value& construct(Value &class_value, const Method &method);
212:
1.127 paf 213: /// execute ops with anti-recoursion check
1.162 paf 214: void recoursion_checked_execute(/*const String& name, */ArrayOperation& ops) {
1.128 paf 215: // anti_endless_execute_recoursion
216: if(++anti_endless_execute_recoursion==ANTI_ENDLESS_EXECUTE_RECOURSION) {
217: anti_endless_execute_recoursion=0; // give @exception a chance
1.184 misha 218: throw Exception(PARSER_RUNTIME,
1.162 paf 219: 0, //&name,
1.128 paf 220: "call canceled - endless recursion detected");
221: }
1.147 paf 222: execute(ops); // execute it
1.128 paf 223: anti_endless_execute_recoursion--;
224: }
1.40 paf 225:
1.207 moko 226: uint json_string_recoursion_go_down(){
1.206 misha 227: if(++anti_endless_json_string_recoursion==ANTI_ENDLESS_JSON_STRING_RECOURSION){
228: anti_endless_json_string_recoursion=0;
229: throw Exception(PARSER_RUNTIME,
230: 0,
231: "call canceled - endless json recursion detected");
232: }
1.207 moko 233: return anti_endless_json_string_recoursion;
1.206 misha 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.209 misha 322: /// returns the mime type of 'user_file_name'
323: const String& mime_type_of(const String* file_name);
324:
1.80 paf 325: /// returns the mime type of 'user_file_name_cstr'
1.162 paf 326: const String& mime_type_of(const char* user_file_name_cstr);
1.80 paf 327:
1.117 paf 328: /// returns current SQL connection if any
1.162 paf 329: SQL_Connection* connection(bool fail_on_error=true) {
330: if(fail_on_error && !fconnection)
1.184 misha 331: throw Exception(PARSER_RUNTIME,
1.162 paf 332: 0,
1.117 paf 333: "outside of 'connect' operator");
334:
335: return fconnection;
1.133 paf 336: }
337:
1.162 paf 338: void set_interrupted(bool ainterrupted) { finterrupted=ainterrupted; }
339: bool get_interrupted() { return finterrupted; }
1.158 paf 340:
1.181 paf 341: void set_skip(Skip askip) { fskip=askip; }
342: Skip get_skip() { return fskip; }
343:
1.196 misha 344: void set_in_cycle(int adelta) { fin_cycle+=adelta; }
345: bool get_in_cycle() { return fin_cycle>0; }
346:
1.17 paf 347: public:
1.22 paf 348:
1.61 paf 349: /// info from web server
1.162 paf 350: Request_info& request_info;
351:
352: /// info about ServerAPI
353: SAPI_Info& sapi_info;
354:
355: /// source, client, mail charsets
356: Request_charsets charsets;
1.53 paf 357:
1.154 paf 358: /// 'MAIN' class conglomerat & operators are methods of this class
1.162 paf 359: VStateless_class& main_class;
1.86 paf 360: /// $form:elements
1.162 paf 361: VForm& form;
1.140 paf 362: /// $mail
1.162 paf 363: VMail& mail;
1.86 paf 364: /// $response:elements
1.162 paf 365: VResponse& response;
1.86 paf 366: /// $cookie:elements
1.162 paf 367: VCookie& cookie;
1.183 misha 368: /// $console
369: VConsole& console;
1.70 paf 370:
1.148 paf 371: /// classes configured data
1.193 misha 372: HashString<void*> classes_conf;
1.85 paf 373:
1.148 paf 374: public: // status read methods
1.76 paf 375:
1.148 paf 376: VMethodFrame *get_method_frame() { return method_frame; }
1.162 paf 377: Value& get_self();
378: #define GET_SELF(request, type) (static_cast<type &>(request.get_self()))
379: /* for strange reason call to this:
380: r.get_self<VHash>()
381: refuses to compile
1.87 paf 382:
1.162 paf 383: template<typename T> T& get_self() {
384: return *static_cast<T*>(get_self().get());
385: }
386: */
1.6 paf 387:
1.205 moko 388: /// public for ^reflection:copy[]
389: void put_element(Value& ncontext, const String& name, Value* value);
390:
1.173 paf 391: /// for @main[]
392: const String* execute_virtual_method(Value& aself, const String& method_name);
393:
1.204 moko 394: /// executes parser method, use op_call(frame) to execute native method
395: void execute_method(VMethodFrame& aframe);
396:
1.173 paf 397: //{ for @conf[filespec] and @auto[filespec] and parser://method/call
398: const String* execute_method(Value& aself,
1.190 misha 399: const Method& method, Value* optional_param,
1.173 paf 400: bool do_return_string);
401: struct Execute_nonvirtual_method_result {
402: const String* string;
403: Method* method;
404: Execute_nonvirtual_method_result(): string(0), method(0) {}
405: };
406: Execute_nonvirtual_method_result execute_nonvirtual_method(VStateless_class& aclass,
1.185 misha 407: const String& method_name,
408: VString* optional_param,
1.173 paf 409: bool do_return_string);
410: //}
411:
1.162 paf 412: #ifdef XML
413: public: // charset helpers
1.67 paf 414:
1.162 paf 415: /// @see Charset::transcode
1.180 paf 416: xmlChar* transcode(const String& s);
1.162 paf 417: /// @see Charset::transcode
1.180 paf 418: xmlChar* transcode(const String::Body s);
1.162 paf 419: /// @see Charset::transcode
1.180 paf 420: const String& transcode(const xmlChar* s);
1.89 parser 421:
1.162 paf 422: #endif
1.136 paf 423:
424: private:
425:
426: /// already executed some @conf method
427: bool configure_admin_done;
428:
1.162 paf 429: void configure_admin(VStateless_class& conf_class);
1.177 paf 430:
431: void configure();
1.99 parser 432:
1.7 paf 433: private: // compile.C
434:
1.189 misha 435: ArrayClass& compile(VStateless_class* aclass,
1.162 paf 436: const char* source, const String* main_alias,
1.175 paf 437: uint file_no,
438: int line_no_offset);
1.7 paf 439:
440: private: // execute.C
1.9 paf 441:
1.191 misha 442: Value& get_element(Value& ncontext, const String& name);
1.22 paf 443:
1.58 paf 444: private: // defaults
445:
1.162 paf 446: const String::Language fdefault_lang;
1.80 paf 447:
448: private: // mime types
449:
450: /// $MAIN:MIME-TYPES
451: Table *mime_types;
1.22 paf 452:
1.39 paf 453: private: // lang manipulation
1.22 paf 454:
1.162 paf 455: String::Language set_lang(String::Language alang) {
456: String::Language result=flang;
1.39 paf 457: flang=alang;
458: return result;
459: }
1.162 paf 460: void restore_lang(String::Language alang) {
1.39 paf 461: flang=alang;
462: }
463:
1.117 paf 464: private: // connection manipulation
465:
1.162 paf 466: SQL_Connection* set_connection(SQL_Connection* aconnection) {
467: SQL_Connection* result=fconnection;
1.117 paf 468: fconnection=aconnection;
469: return result;
470: }
1.162 paf 471: void restore_connection(SQL_Connection* aconnection) {
1.117 paf 472: fconnection=aconnection;
473: }
474:
475: private:
476:
1.162 paf 477: void output_result(VFile* body_file, bool header_only, bool as_attachment);
1.148 paf 478: };
479:
480: /// Auto-object used to save request context across ^try body
481: class Request_context_saver {
482: Request& fr;
483:
484: /// exception stack trace
1.165 paf 485: size_t exception_trace_top;
486: size_t exception_trace_bottom;
1.148 paf 487: /// execution stack
1.162 paf 488: size_t stack;
1.166 paf 489: uint anti_endless_execute_recoursion;
1.206 misha 490: uint anti_endless_json_string_recoursion;
1.148 paf 491: /// contexts
1.162 paf 492: VMethodFrame* method_frame;
493: Value* rcontext;
494: WContext* wcontext;
1.148 paf 495: /// current language
1.162 paf 496: String::Language flang;
1.148 paf 497: /// current connection
1.162 paf 498: SQL_Connection* fconnection;
1.126 paf 499:
1.148 paf 500: public:
501: Request_context_saver(Request& ar) :
1.171 paf 502: fr(ar),
1.165 paf 503: exception_trace_top(ar.exception_trace.top_index()),
504: exception_trace_bottom(ar.exception_trace.bottom_index()),
505: stack(ar.stack.top_index()),
1.166 paf 506: anti_endless_execute_recoursion(ar.anti_endless_execute_recoursion),
1.206 misha 507: anti_endless_json_string_recoursion(ar.anti_endless_json_string_recoursion),
1.148 paf 508: method_frame(ar.method_frame),
509: rcontext(ar.rcontext),
510: wcontext(ar.wcontext),
511: flang(ar.flang),
1.171 paf 512: fconnection(ar.fconnection) {}
1.153 paf 513: void restore() {
1.165 paf 514: fr.exception_trace.set_top_index(exception_trace_top);
515: fr.exception_trace.set_bottom_index(exception_trace_bottom);
516: fr.stack.set_top_index(stack);
1.166 paf 517: fr.anti_endless_execute_recoursion=anti_endless_execute_recoursion;
1.206 misha 518: fr.anti_endless_json_string_recoursion=anti_endless_json_string_recoursion;
1.157 paf 519: fr.method_frame=method_frame, fr.rcontext=rcontext; fr.wcontext=wcontext;
1.148 paf 520: fr.flang=flang;
521: fr.fconnection=fconnection;
522: }
1.39 paf 523: };
524:
1.61 paf 525: /// Auto-object used for temporary changing Request::flang.
1.39 paf 526: class Temp_lang {
527: Request& frequest;
1.162 paf 528: String::Language saved_lang;
1.39 paf 529: public:
1.162 paf 530: Temp_lang(Request& arequest, String::Language alang) :
1.39 paf 531: frequest(arequest),
532: saved_lang(arequest.set_lang(alang)) {
533: }
534: ~Temp_lang() {
535: frequest.restore_lang(saved_lang);
1.117 paf 536: }
537: };
538:
539: /// Auto-object used for temporary changing Request::fconnection.
540: class Temp_connection {
541: Request& frequest;
1.162 paf 542: SQL_Connection* saved_connection;
1.117 paf 543: public:
1.162 paf 544: Temp_connection(Request& arequest, SQL_Connection* aconnection) :
1.117 paf 545: frequest(arequest),
546: saved_connection(arequest.set_connection(aconnection)) {
547: }
548: ~Temp_connection() {
549: frequest.restore_connection(saved_connection);
1.39 paf 550: }
1.91 parser 551: };
552:
1.196 misha 553: /// Auto-object used for break out of cycle check
554: class InCycle {
555: Request& frequest;
556: public:
557: InCycle(Request& arequest) : frequest(arequest) {
558: frequest.set_in_cycle(1);
559: }
560: ~InCycle() {
561: frequest.set_in_cycle(-1);
562: }
563: };
1.91 parser 564:
1.162 paf 565: // defines for externs
1.91 parser 566:
1.170 paf 567: #define EXCEPTION_HANDLED_PART_NAME "handled"
568:
1.162 paf 569:
570: // externs
571:
572: extern const String main_method_name;
573: extern const String auto_method_name;
574: extern const String body_name;
1.186 misha 575:
1.162 paf 576: extern const String exception_type_part_name;
577: extern const String exception_source_part_name;
578: extern const String exception_comment_part_name;
579: extern const String exception_handled_part_name;
1.91 parser 580:
1.162 paf 581: // defines for statics
1.91 parser 582:
1.162 paf 583: #define MAIN_CLASS_NAME "MAIN"
584: #define AUTO_FILE_NAME "auto.p"
1.1 paf 585:
586: #endif
E-mail: