--- parser3/src/main/pa_request.C 2016/04/03 23:07:44 1.353 +++ parser3/src/main/pa_request.C 2016/11/03 16:17:37 1.363 @@ -32,7 +32,7 @@ #include "pa_vconsole.h" #include "pa_vdate.h" -volatile const char * IDENT_PA_REQUEST_C="$Id: pa_request.C,v 1.353 2016/04/03 23:07:44 moko Exp $" IDENT_PA_REQUEST_H IDENT_PA_REQUEST_CHARSETS_H IDENT_PA_REQUEST_INFO_H IDENT_PA_VCONSOLE_H; +volatile const char * IDENT_PA_REQUEST_C="$Id: pa_request.C,v 1.363 2016/11/03 16:17:37 moko Exp $" IDENT_PA_REQUEST_H IDENT_PA_REQUEST_CHARSETS_H IDENT_PA_REQUEST_INFO_H IDENT_PA_VCONSOLE_H; // consts @@ -44,6 +44,9 @@ const char* UNHANDLED_EXCEPTION_CONTENT_ /// content type of response when no $MAIN:defaults.content-type defined const char* DEFAULT_CONTENT_TYPE="text/html"; +const uint EXECUTE_RECOURSION_LIMIT=1000; +const uint LOOP_LIMIT=20000; + // defines for globals #define MAIN_METHOD_NAME "main" @@ -64,11 +67,18 @@ const String exception_source_part_name( const String exception_comment_part_name(EXCEPTION_COMMENT_PART_NAME); const String exception_handled_part_name(EXCEPTION_HANDLED_PART_NAME); +int pa_execute_recoursion_limit=EXECUTE_RECOURSION_LIMIT; +int pa_loop_limit=LOOP_LIMIT; + // defines for statics #define CHARSETS_NAME "CHARSETS" #define MIME_TYPES_NAME "MIME-TYPES" #define STRICT_VARS_NAME "STRICT-VARS" +#define PROTOTYPE_NAME "OBJECT-PROTOTYPE" +#define LIMITS_NAME "LIMITS" +#define RECOURSION_LIMIT_NAME "max_recoursion" +#define LOOP_LIMIT_NAME "max_loop" #define CONF_METHOD_NAME "conf" #define POST_PROCESS_METHOD_NAME "postprocess" #define CLASS_PATH_NAME "CLASS_PATH" @@ -83,6 +93,11 @@ static const String charsets_name(CHARSE static const String main_class_name(MAIN_CLASS_NAME); static const String mime_types_name(MIME_TYPES_NAME); static const String strict_vars_name(STRICT_VARS_NAME); +static const String prototype_name(PROTOTYPE_NAME); +static const String limits_name(LIMITS_NAME); +static const String recoursion_limit_name(RECOURSION_LIMIT_NAME); +static const String loop_limit_name(LOOP_LIMIT_NAME); + static const String conf_method_name(CONF_METHOD_NAME); static const String post_process_method_name(POST_PROCESS_METHOD_NAME); static const String class_path_name(CLASS_PATH_NAME); @@ -126,7 +141,7 @@ Request::Request(SAPI_Info& asapi_info, // public request_info(arequest_info), sapi_info(asapi_info), - charsets(UTF8_charset, UTF8_charset, UTF8_charset), // default charsets + charsets(pa_UTF8_charset, pa_UTF8_charset, pa_UTF8_charset), // default charsets main_class(VClassMAIN_create()), form(*new VForm(charsets, arequest_info)), @@ -160,6 +175,7 @@ Request::Request(SAPI_Info& asapi_info, methoded_array().register_directly_used(*this); /// methodless + // env class put_class(new VEnv(asapi_info)); // status class @@ -170,10 +186,11 @@ Request::Request(SAPI_Info& asapi_info, put_class(&cookie); // console class put_class(&console); + /// methoded + // response class put_class(&response); - // form class put_class(&form); // mail class @@ -196,36 +213,30 @@ Request::~Request() { Value& Request::get_self() { return method_frame/*always have!*/->self(); } -Value* Request::get_class(const String& name){ - Value* result=classes().get(name); +VStateless_class* Request::get_class(const String& name){ + VStateless_class* result=classes().get(name); if(!result) if(Value* value=main_class.get_element(autouse_method_name)) if(Junction* junction=value->get_junction()) if(const Method *method=junction->method) { Value *vname=new VString(name); - VMethodFrame frame(*method, 0 /*no parent*/, main_class); - - frame.store_params(&vname, 1); - // we don't need the result - execute_method(frame); - + CONSTRUCTOR_FRAME_ACTION(*method, 0 /*no parent*/, main_class, { + frame.store_params(&vname, 1); + // we don't need the result + call(frame); + }); result=classes().get(name); } - return result; } -static void load_charset(HashStringValue::key_type akey, - HashStringValue::value_type avalue, - Request_charsets* charsets) { - const String::Body NAME=String(akey, String::L_CLEAN).change_case(charsets->source(), String::CC_UPPER); - ::charsets.load_charset(*charsets, NAME, avalue->as_string()); +static void load_charset(HashStringValue::key_type akey, HashStringValue::value_type avalue, Request_charsets* charsets) { + pa_charsets.load_charset(*charsets, akey, avalue->as_string()); } + void Request::configure_admin(VStateless_class& conf_class) { if(configure_admin_done) - throw Exception(PARSER_RUNTIME, - 0, - "parser already configured"); + throw Exception(PARSER_RUNTIME, 0, "parser already configured"); configure_admin_done=true; // charsets must only be specified in method_frame config @@ -241,9 +252,7 @@ void Request::configure_admin(VStateless if(HashStringValue* charsets=vcharsets->get_hash()) charsets->for_each(load_charset, &this->charsets); else - throw Exception(PARSER_RUNTIME, - 0, - "$" MAIN_CLASS_NAME ":" CHARSETS_NAME " must be hash"); + throw Exception(PARSER_RUNTIME, 0, "$" MAIN_CLASS_NAME ":" CHARSETS_NAME " must be hash"); } } @@ -252,13 +261,43 @@ void Request::configure_admin(VStateless if(Value* strict_vars=conf_class.get_element(strict_vars_name)) { if(strict_vars->is_bool()) VVoid::strict_vars=strict_vars->as_bool(); - else - throw Exception(PARSER_RUNTIME, - 0, - "$" MAIN_CLASS_NAME ":" STRICT_VARS_NAME " must be bool"); + else + throw Exception(PARSER_RUNTIME, 0, "$" MAIN_CLASS_NAME ":" STRICT_VARS_NAME " must be bool"); + } +#endif + +#ifdef OBJECT_PROTOTYPE + VClass::prototype=true; + if(Value* prototype=conf_class.get_element(prototype_name)) { + if(prototype->is_bool()) + VClass::prototype=prototype->as_bool(); + else + throw Exception(PARSER_RUNTIME, 0, "$" MAIN_CLASS_NAME ":" PROTOTYPE_NAME " must be bool"); } #endif + Value* limits=conf_class.get_element(limits_name); + + pa_loop_limit=LOOP_LIMIT; + if(limits) + if(Value* loop_limit=limits->get_element(loop_limit_name)) { + if(loop_limit->is_evaluated_expr()) { + pa_loop_limit=loop_limit->as_int(); + if(pa_loop_limit==0) pa_loop_limit=INT_MAX; + } else + throw Exception(PARSER_RUNTIME, 0, "$" MAIN_CLASS_NAME ":" LOOP_LIMIT_NAME " must be int"); + } + + pa_execute_recoursion_limit=EXECUTE_RECOURSION_LIMIT; + if(limits) + if(Value* recoursion_limit=limits->get_element(recoursion_limit_name)) { + if(recoursion_limit->is_evaluated_expr()) { + pa_execute_recoursion_limit=recoursion_limit->as_int(); + if(pa_execute_recoursion_limit==0) pa_execute_recoursion_limit=INT_MAX; + } else + throw Exception(PARSER_RUNTIME, 0, "$" MAIN_CLASS_NAME ":" RECOURSION_LIMIT_NAME " must be int"); + } + // configure method_frame options // until someone with less privileges have overriden them methoded_array().configure_admin(*this); @@ -402,12 +441,11 @@ void Request::core(const char* config_fi if(const Method *method=junction->method) { // preparing to pass parameters to // @postprocess[data] - VMethodFrame frame(*method, 0 /*no parent*/, main_class); - - frame.store_params(&body_value, 1); - execute_method(frame); - - body_value=&frame.result().as_value(); + METHOD_FRAME_ACTION(*method, 0 /*no parent*/, main_class, { + frame.store_params(&body_value, 1); + call(frame); + body_value=&frame.result(); + }); } VFile* body_file=body_value->as_vfile(flang, &charsets); @@ -465,13 +503,12 @@ void Request::core(const char* config_fi // execute ^unhandled_exception[exception;stack] exception_trace.clear(); // forget all about previous life, in case there would be error inside of this method, error handled would not be mislead by old stack contents (see extract_origin) - VMethodFrame frame(*method, 0 /*no caller*/, main_class); Value *params[]={&details.vhash, new VTable(&stack_trace)}; - - frame.store_params(params, 2); - execute_method(frame); - - body_string=&frame.result().as_string(); + METHOD_FRAME_ACTION(*method, 0 /*no caller*/, main_class, { + frame.store_params(params, 2); + call(frame); + body_string=&frame.result().as_string(); + }); } } } @@ -593,13 +630,10 @@ void Request::use_file(VStateless_class& } } -void Request::use_buf(VStateless_class& aclass, - const char* source, const String* main_alias, - uint file_no, - int line_no_offset) { - // temporary zero @conf so to maybe-replace it in compiled code +void Request::use_buf(VStateless_class& aclass, const char* source, const String* main_alias, uint file_no, int line_no_offset) { + // temporary zero @conf to avoid it second execution Temp_method temp_method_conf(aclass, conf_method_name, 0); - // temporary zero @auto so to maybe-replace it in compiled code + // temporary zero @auto to avoid it second execution Temp_method temp_method_auto(aclass, auto_method_name, 0); // compile loaded classes @@ -612,16 +646,12 @@ void Request::use_buf(VStateless_class& VStateless_class& cclass=*cclasses.get(i); // locate and execute possible @conf[] static - Execute_nonvirtual_method_result executed=execute_nonvirtual_method(cclass, - conf_method_name, vfilespec, - false/*no string result needed*/); + Execute_nonvirtual_method_result executed=execute_nonvirtual_method(cclass, conf_method_name, vfilespec, false/*no string result needed*/); if(executed.method) configure_admin(cclass/*, executed.method->name*/); // locate and execute possible @auto[] static - execute_nonvirtual_method(cclass, - auto_method_name, vfilespec, - false/*no result needed*/); + execute_nonvirtual_method(cclass, auto_method_name, vfilespec, false/*no result needed*/); cclass.enable_default_setter(); }