|
|
| version 1.156, 2002/10/15 14:28:57 | version 1.160.2.7, 2003/01/30 14:59:43 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: request class decl. | Parser: request class decl. |
| Copyright (c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com) | Copyright (c) 2001, 2003 ArtLebedev Group (http://www.artlebedev.com) |
| Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) | Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) |
| */ | */ |
| Line 11 | Line 11 |
| static const char* IDENT_REQUEST_H="$Date$"; | static const char* IDENT_REQUEST_H="$Date$"; |
| #include "pa_pool.h" | #include "pa_pool.h" |
| #include "pa_request_info.h" | |
| #include "pa_hash.h" | #include "pa_hash.h" |
| #include "pa_wcontext.h" | #include "pa_wcontext.h" |
| #include "pa_value.h" | #include "pa_value.h" |
| Line 25 static const char* IDENT_REQUEST_H="$Dat | Line 26 static const char* IDENT_REQUEST_H="$Dat |
| #include "pa_vrequest.h" | #include "pa_vrequest.h" |
| #include "pa_vresponse.h" | #include "pa_vresponse.h" |
| #include "pa_vcookie.h" | #include "pa_vcookie.h" |
| #include "pa_sql_driver_manager.h" | #include "pa_request_info.h" |
| #include "pa_request_charsets.h" | |
| #ifdef RESOURCES_DEBUG | #ifdef RESOURCES_DEBUG |
| #include <sys/resource.h> | #include <sys/resource.h> |
| Line 33 static const char* IDENT_REQUEST_H="$Dat | Line 35 static const char* IDENT_REQUEST_H="$Dat |
| // consts | // consts |
| #define MAIN_METHOD_NAME "main" | |
| const uint ANTI_ENDLESS_EXECUTE_RECOURSION=500; | const uint ANTI_ENDLESS_EXECUTE_RECOURSION=500; |
| // defines | // defines |
| Line 56 class Methoded; | Line 57 class Methoded; |
| class VMethodFrame; | class VMethodFrame; |
| /// Main workhorse. | /// Main workhorse. |
| class Request : public Pooled { | class Request: public PA_Object { |
| friend class Temp_lang; | friend class Temp_lang; |
| friend class Temp_connection; | friend class Temp_connection; |
| friend class Request_context_saver; | friend class Request_context_saver; |
| friend class Temp_request_self; | friend class Temp_request_self; |
| /// all files and classes and other hard-to-place allocations go to this pool | |
| Pool fpool; | |
| ///@{ core data | |
| typedef Hash<ConstStringPtr, VStateless_classPtr> classes_type; | |
| /// classes | |
| classes_type fclasses; | |
| /// already used files to avoid cyclic uses | |
| Hash<ConstStringPtr, bool> used_files; | |
| /** endless execute(execute(... preventing counter | |
| @see ANTI_ENDLESS_EXECUTE_RECOURSION | |
| */ | |
| uint anti_endless_execute_recoursion; | |
| ///@} | |
| public: | public: |
| //@{ request processing status | |
| /// exception stack trace | |
| Stack<ConstStringPtr> exception_trace; | |
| /// execution stack | |
| Stack<void *> stack; | |
| /// contexts | |
| VMethodFrame *method_frame; | |
| Value *rcontext; | |
| WContext *wcontext; | |
| /// current language | |
| uchar flang; | |
| /// current connection | |
| SQL_Connection *fconnection; | |
| //@} | |
| /// interrupted flag, raised on signals [SIGPIPE] | |
| bool finterrupted; | |
| public: | |
| /// all files and classes and other hard-to-place allocations go to this pool | |
| Pool& pool() { return fpool; } | |
| #ifdef RESOURCES_DEBUG | #ifdef RESOURCES_DEBUG |
| /// measures | /// measures |
| Line 69 public: | Line 112 public: |
| double sql_request_time; | double sql_request_time; |
| #endif | #endif |
| /// some information from web server | Request( |
| class Info { | Request_info& ainfo, |
| public: | |
| const char *document_root; | |
| const char *path_translated; | |
| const char *method; | |
| const char *query_string; | |
| const char *uri; | |
| const char *content_type; | |
| size_t content_length; | |
| const char *cookie; | |
| bool mail_received; | |
| }; | |
| Request(Pool& apool, | |
| Info& ainfo, | |
| uchar adefault_lang, ///< all tainted data default untainting lang | uchar adefault_lang, ///< all tainted data default untainting lang |
| bool status_allowed ///< status class allowed | bool status_allowed ///< status class allowed |
| ); | ); |
| ~Request(); | ~Request(); |
| /// global classes | /// global classes |
| Hash& classes() { return fclasses; } | classes_type& classes() { return fclasses; } |
| /** | /** |
| core request processing | core request processing |
| Line 106 public: | Line 135 public: |
| /// executes ops | /// executes ops |
| void execute(const Array& ops); // execute.C | void execute(const Array& ops); // execute.C |
| /// execute ops with anti-recoursion check | /// execute ops with anti-recoursion check |
| void recoursion_checked_execute(const String *name, const Array& ops) { | void recoursion_checked_execute(ConstStringPtr name, const Array& ops) { |
| // anti_endless_execute_recoursion | // anti_endless_execute_recoursion |
| if(++anti_endless_execute_recoursion==ANTI_ENDLESS_EXECUTE_RECOURSION) { | if(++anti_endless_execute_recoursion==ANTI_ENDLESS_EXECUTE_RECOURSION) { |
| anti_endless_execute_recoursion=0; // give @exception a chance | anti_endless_execute_recoursion=0; // give @exception a chance |
| Line 119 public: | Line 148 public: |
| } | } |
| /// compiles the file, maybe forcing it's class @a name and @a base_class. | /// compiles the file, maybe forcing it's class @a name and @a base_class. |
| VStateless_class *use_file(VStateless_class& aclass, | VStateless_classPtr use_file(VStateless_class& aclass, |
| const String& file_name, | ConstStringPtr file_name, |
| bool ignore_class_path=false, | bool ignore_class_path=false, |
| bool fail_on_read_problem=true, bool fail_on_file_absence=true); // core.C | bool fail_on_read_problem=true, bool fail_on_file_absence=true); // core.C |
| /// compiles a @a source buffer | /// compiles a @a source buffer |
| VStateless_class *use_buf(VStateless_class& aclass, | VStateless_classPtr use_buf(VStateless_class& aclass, |
| const char *source, | const char *source, |
| const String& filespec, const char *filespec_cstr); // core.C | const String& filespec, const char *filespec_cstr); // core.C |
| /// processes any code-junction there may be inside of @a value | /// processes any code-junction there may be inside of @a value |
| StringOrValue process(Value& input_value, bool intercept_string=true); // execute.C | StringOrValue process(ValuePtr input_value, bool intercept_string=true); // execute.C |
| //@{ convinient helpers | //@{ convinient helpers |
| const String& process_to_string(Value& input_value) { | ConstStringPtr process_to_string(ValuePtr input_value) { |
| return process(input_value, true/*intercept_string*/).as_string(); | return process(input_value, true/*intercept_string*/).as_string(&pool()); |
| } | } |
| Value& process_to_value(Value& input_value, bool intercept_string=true) { | ValuePtr process_to_value(ValuePtr input_value, bool intercept_string=true) { |
| return process(input_value, intercept_string).as_value(); | return process(input_value, intercept_string).as_value(); |
| } | } |
| //@} | //@} |
| Line 142 public: | Line 171 public: |
| #define DEFINE_DUAL(modification) \ | #define DEFINE_DUAL(modification) \ |
| void write_##modification##_lang(StringOrValue dual) { \ | void write_##modification##_lang(StringOrValue dual) { \ |
| if(const String *string=dual.get_string()) \ | if(ConstStringPtr string=dual.get_string()) \ |
| write_##modification##_lang(*string); \ | write_##modification##_lang(*string); \ |
| else \ | else \ |
| write_##modification##_lang(*dual.get_value()); \ | write_##modification##_lang(dual.get_value()); \ |
| } | } |
| #define DEFINE_DUAL_CHECKED(modification) \ | #define DEFINE_DUAL_CHECKED(modification) \ |
| void write_##modification##_lang(StringOrValue dual, const String *origin) { \ | void write_##modification##_lang(StringOrValue dual, ConstStringPtr origin) { \ |
| if(const String *string=dual.get_string()) \ | if(ConstStringPtr string=dual.get_string()) \ |
| write_##modification##_lang(*string); \ | write_##modification##_lang(*string); \ |
| else \ | else \ |
| write_##modification##_lang(*dual.get_value(), origin); \ | write_##modification##_lang(dual.get_value(), origin); \ |
| } | } |
| /// appending, sure of clean string inside | /// appending, sure of clean string inside |
| Line 161 public: | Line 190 public: |
| String::UL_CLEAN | flang&String::UL_OPTIMIZE_BIT); | String::UL_CLEAN | flang&String::UL_OPTIMIZE_BIT); |
| } | } |
| /// appending sure value, that would be converted to clean string | /// appending sure value, that would be converted to clean string |
| void write_no_lang(Value& avalue) { | void write_no_lang(ValuePtr avalue) { |
| if(wcontext->get_in_expression()) | if(wcontext->get_in_expression()) |
| wcontext->write(avalue); | wcontext->write(avalue); |
| else | else |
| wcontext->write(avalue, | wcontext->write(pool(), avalue, |
| String::UL_CLEAN | flang&String::UL_OPTIMIZE_BIT); | String::UL_CLEAN | flang&String::UL_OPTIMIZE_BIT); |
| } | } |
| //DEFINE_DUAL(no) | |
| /// appending string, passing language built into string being written | /// appending string, passing language built into string being written |
| void write_pass_lang(const String& astring) { | void write_pass_lang(const String& astring) { |
| wcontext->write(astring, String::UL_PASS_APPENDED); | wcontext->write(astring, String::UL_PASS_APPENDED); |
| } | } |
| /// appending possible string, passing language built into string being written | /// appending possible string, passing language built into string being written |
| void write_pass_lang(Value& avalue) { | void write_pass_lang(ValuePtr avalue) { |
| wcontext->write(avalue, String::UL_PASS_APPENDED); | wcontext->write(pool(), avalue, String::UL_PASS_APPENDED); |
| } | } |
| DEFINE_DUAL(pass) | DEFINE_DUAL(pass) |
| /// appending possible string, assigning untaint language | /// appending possible string, assigning untaint language |
| void write_assign_lang(Value& avalue) { | void write_assign_lang(ValuePtr avalue) { |
| wcontext->write(avalue, flang); | wcontext->write(pool(), avalue, flang); |
| } | } |
| /// appending possible string, assigning untaint language | /// appending possible string, assigning untaint language |
| void write_assign_lang(Value& avalue, const String *origin) { | void write_assign_lang(ValuePtr avalue, ConstStringPtr origin) { |
| wcontext->write(avalue, flang, origin); | wcontext->write(pool(), avalue, flang, origin); |
| } | } |
| /// appending string, assigning untaint language | /// appending string, assigning untaint language |
| void write_assign_lang(const String& astring) { | void write_assign_lang(const String& astring) { |
| Line 205 public: | Line 233 public: |
| const String& mime_type_of(const char *user_file_name_cstr); | const String& mime_type_of(const char *user_file_name_cstr); |
| /// returns current SQL connection if any | /// returns current SQL connection if any |
| SQL_Connection *connection(const String *source) { | SQL_Connection *connection(ConstStringPtr source) { |
| if(!fconnection && source) | if(!fconnection && source) |
| throw Exception("parser.runtime", | throw Exception("parser.runtime", |
| source, | source, |
| Line 216 public: | Line 244 public: |
| bool origins_mode(); | bool origins_mode(); |
| void interrupt() { finterrupted=true; } | |
| bool interrupted() { return finterrupted; } | |
| public: | public: |
| /// info from web server | /// info from web server |
| Info& info; | Request_info& info; |
| /// user's post data | |
| const char *post_data; size_t post_size; | /// source, client, mail charsets |
| Request_charsets charsets; | |
| /// name of 'main' method | |
| const String main_method_name; | |
| /// 'MAIN' class conglomerat & operators are methods of this class | /// 'MAIN' class conglomerat & operators are methods of this class |
| VClass& main_class; | VClass& main_class; |
| /// $env:fields | /// $env:fields |
| Line 246 public: | Line 275 public: |
| VCookie cookie; | VCookie cookie; |
| /// classes configured data | /// classes configured data |
| Hash classes_conf; | HashStringValue classes_conf; |
| private: | |
| //@{ request processing status | |
| /// exception stack trace | |
| Stack exception_trace; | |
| /// execution stack | |
| Stack stack; | |
| /// contexts | |
| Value *self; | |
| VMethodFrame *method_frame; | |
| Value *rcontext; | |
| WContext *wcontext; | |
| /// current language | |
| uchar flang; | |
| /// current connection | |
| SQL_Connection *fconnection; | |
| //@} | |
| public: // status read methods | public: // status read methods |
| Value *get_self() { return self; } | |
| VMethodFrame *get_method_frame() { return method_frame; } | VMethodFrame *get_method_frame() { return method_frame; } |
| Value *get_self(); | |
| private: // core data | |
| /// classes | |
| Hash fclasses; | |
| /// already used files to avoid cyclic uses | |
| Hash used_files; | |
| /** endless execute(execute(... preventing counter | |
| @see ANTI_ENDLESS_EXECUTE_RECOURSION | |
| */ | |
| uint anti_endless_execute_recoursion; | |
| private: | private: |
| Line 347 private: // connection manipulation | Line 345 private: // connection manipulation |
| private: | private: |
| void output_result(const VFile& body_file, bool header_only); | void output_result(const VFile& body_file, bool header_only, bool as_attachment); |
| }; | }; |
| /// Auto-object used to save request context across ^try body | /// Auto-object used to save request context across ^try body |
| Line 359 class Request_context_saver { | Line 357 class Request_context_saver { |
| /// execution stack | /// execution stack |
| int stack; | int stack; |
| /// contexts | /// contexts |
| Value *self; | |
| VMethodFrame *method_frame; | VMethodFrame *method_frame; |
| Value *rcontext; | Value *rcontext; |
| WContext *wcontext; | WContext *wcontext; |
| Line 372 public: | Line 369 public: |
| Request_context_saver(Request& ar) : | Request_context_saver(Request& ar) : |
| exception_trace(ar.exception_trace.top_index()), | exception_trace(ar.exception_trace.top_index()), |
| stack(ar.stack.top_index()), | stack(ar.stack.top_index()), |
| self(ar.self), | |
| method_frame(ar.method_frame), | method_frame(ar.method_frame), |
| rcontext(ar.rcontext), | rcontext(ar.rcontext), |
| wcontext(ar.wcontext), | wcontext(ar.wcontext), |
| Line 382 public: | Line 378 public: |
| void restore() { | void restore() { |
| fr.exception_trace.top_index(exception_trace); | fr.exception_trace.top_index(exception_trace); |
| fr.stack.top_index(stack); | fr.stack.top_index(stack); |
| fr.self=self; fr.method_frame=method_frame, fr.rcontext=rcontext; fr.wcontext=wcontext; | fr.method_frame=method_frame, fr.rcontext=rcontext; fr.wcontext=wcontext; |
| fr.flang=flang; | fr.flang=flang; |
| fr.fconnection=fconnection; | fr.fconnection=fconnection; |
| } | } |
| }; | }; |
| /// Auto-object used for temporary changing Request::self. | |
| class Temp_request_self { | |
| Request& frequest; | |
| Value *saved_self; | |
| public: | |
| Temp_request_self(Request& arequest, Value& aself) : | |
| frequest(arequest), | |
| saved_self(arequest.self) { | |
| frequest.self=&aself; | |
| } | |
| ~Temp_request_self() { | |
| frequest.self=saved_self; | |
| } | |
| }; | |
| /// Auto-object used for temporary changing Request::flang. | /// Auto-object used for temporary changing Request::flang. |
| class Temp_lang { | class Temp_lang { |
| Request& frequest; | Request& frequest; |
| Line 431 public: | Line 412 public: |
| } | } |
| }; | }; |
| /** | // externs |
| @b method parameters passed in this array. | |
| contains handy typecast ad junction/not junction ensurers | |
| */ | extern StringPtr main_method_name; |
| class MethodParams : public Array { | |
| public: | |
| MethodParams(Pool& pool, const String& amethod_name) : Array(pool), | |
| fmethod_name(amethod_name) { | |
| } | |
| /// handy typecast. I long for templates | |
| Value& get(int index) { | |
| return *static_cast<Value *>(Array::get(index)); | |
| } | |
| /// handy is-value-a-junction ensurer | |
| Value& as_junction(int index, const char *msg) { | |
| return get_as(index, true, msg); | |
| } | |
| /// handy value-is-not-a-junction ensurer | |
| Value& as_no_junction(int index, const char *msg) { | |
| return get_as(index, false, msg); | |
| } | |
| /// handy expression auto-processing to double | |
| double as_double(int index, const char *msg, Request& r) { | |
| return get_processed(index, msg, r).as_double(); | |
| } | |
| /// handy expression auto-processing to int | |
| int as_int(int index, const char *msg, Request& r) { | |
| return get_processed(index, msg, r).as_int(); | |
| } | |
| /// handy expression auto-processing to bool | |
| bool as_bool(int index, const char *msg, Request& r) { | |
| return get_processed(index, msg, r).as_bool(); | |
| } | |
| /// handy string ensurer | |
| const String& as_string(int index, const char *msg) { | |
| return as_no_junction(index, msg).as_string(); | |
| } | |
| private: | |
| /// handy value-is/not-a-junction ensurer | |
| Value& get_as(int index, bool as_junction, const char *msg) { | |
| Value& result=get(index); | |
| if((result.get_junction()!=0) ^ as_junction) | |
| throw Exception("parser.runtime", | |
| &fmethod_name, | |
| "%s (parameter #%d)", msg, 1+index); | |
| return result; | |
| } | |
| Value& get_processed(int index, const char *msg, Request& r) { | |
| return r.process_to_value(as_junction(index, msg), 0/*no name*/); | |
| } | |
| private: | |
| const String& fmethod_name; | |
| }; | |
| #endif | #endif |