--- parser3/src/classes/op.C 2010/07/05 05:54:46 1.201 +++ parser3/src/classes/op.C 2013/08/21 12:11:13 1.215 @@ -1,12 +1,10 @@ /** @file Parser: parser @b operators. - Copyright (c) 2001-2009 ArtLebedev Group (http://www.artlebedev.com) + Copyright (c) 2001-2012 Art. Lebedev Studio (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) */ -static const char * const IDENT_OP_C="$Date: 2010/07/05 05:54:46 $"; - #include "classes.h" #include "pa_vmethod_frame.h" @@ -20,6 +18,8 @@ static const char * const IDENT_OP_C="$D #include "pa_vclass.h" #include "pa_charset.h" +volatile const char * IDENT_OP_C="$Id: op.C,v 1.215 2013/08/21 12:11:13 moko Exp $"; + // limits #define MAX_LOOPS 20000 @@ -81,6 +81,7 @@ public: ULN("optimized-html", HTML|String::L_OPTIMIZE_BIT); ULN("regex", REGEX); ULN("parser-code", PARSER_CODE); + ULN("json", JSON); #undef ULN } } untaint_lang_name2enum; @@ -103,13 +104,10 @@ static void _if(Request& r, MethodParams r.process_write(*params.get(i)); } -static String::Language get_untaint_lang(MethodParams& params, int index){ - const String& lang_name=params.as_string(index, "lang must be string"); +String::Language get_untaint_lang(const String& lang_name){ String::Language lang=untaint_lang_name2enum.get(lang_name); if(!lang) - throw Exception(PARSER_RUNTIME, - &lang_name, - "invalid taint language"); + throw Exception(PARSER_RUNTIME, &lang_name, "invalid taint language"); return lang; } @@ -118,7 +116,7 @@ static void _untaint(Request& r, MethodP if(params.count()==1) lang=String::L_AS_IS; // mark as simply 'as-is'. useful in html from sql else - lang=get_untaint_lang(params, 0); + lang=get_untaint_lang(params.as_string(0, "lang must be string")); { Value& vbody=params.as_junction(params.count()-1, "body must be code"); @@ -134,7 +132,7 @@ static void _taint(Request& r, MethodPar if(params.count()==1) lang=String::L_TAINTED; // mark as simply 'tainted'. useful in table:create else - lang=get_untaint_lang(params, 0); + lang=get_untaint_lang(params.as_string(0, "lang must be string")); { Value& vbody=params.as_no_junction(params.count()-1, "body must not be code"); @@ -144,6 +142,13 @@ static void _taint(Request& r, MethodPar } } +static void _apply_taint(Request& r, MethodParams& params) { + String::Language lang=params.count()==1 ? String::L_AS_IS : get_untaint_lang(params.as_string(0, "lang must be string")); + const String &sbody=params.as_string(params.count()-1, "body must be string"); + String::Body result_body=sbody.cstr_to_string_body_untaint(lang, r.connection(false), &r.charsets); + r.write_pass_lang(*new String(result_body, String::L_AS_IS)); +} + static void _process(Request& r, MethodParams& params) { Method* main_method; @@ -170,36 +175,30 @@ static void _process(Request& r, MethodP // temporary zero @auto so it wouldn't be auto-called in Request::use_buf Temp_method temp_method_auto(*target_class, auto_method_name, 0); - size_t options_index=index+1; - HashStringValue* options=0; - if(options_indexget(PROCESS_MAIN_OPTION_NAME)) { - valid_options++; - main_alias=&vmain_alias->as_string(); - } - if(Value* vfile_alias=options->get(PROCESS_FILE_OPTION_NAME)) { - valid_options++; - file_alias=&vfile_alias->as_string(); - } - if(Value* vline_no_alias_offset=options->get(PROCESS_LINENO_OPTION_NAME)) { - valid_options++; - line_no_alias_offset=vline_no_alias_offset->as_int(); + + size_t options_index=index+1; + if(options_indexget(PROCESS_MAIN_OPTION_NAME)) { + valid_options++; + main_alias=&vmain_alias->as_string(); + } + if(Value* vfile_alias=options->get(PROCESS_FILE_OPTION_NAME)) { + valid_options++; + file_alias=&vfile_alias->as_string(); + } + if(Value* vline_no_alias_offset=options->get(PROCESS_LINENO_OPTION_NAME)) { + valid_options++; + line_no_alias_offset=vline_no_alias_offset->as_int(); + } + + if(valid_options!=options->count()) + throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); } - - if(valid_options!=options->count()) - throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); - } uint processe_file_no=file_alias? r.register_file(r.absolute(*file_alias)) @@ -220,10 +219,10 @@ static void _process(Request& r, MethodP // after restoring current-request-lang // maybe-execute @main[] if(main_method) { - // temporarily set method_frame's self to target_self - Temp_method_frame_self tmfs(*r.get_method_frame(), *target_self); - // execute! - r.execute(*main_method->parser_code); + VMethodFrame frame(*main_method, r.get_method_frame()->caller(), *target_self); + frame.empty_params(); + r.op_call(frame); + r.write_pass_lang(frame.result()); } } @@ -290,12 +289,12 @@ static void _use(Request& r, MethodParam Value& vfile=params.as_no_junction(0, FILE_NAME_MUST_NOT_BE_CODE); // _use could be called from the parser3 method only, so caller is always defined - r.use_file(r.main_class, vfile.as_string(), r.get_method_filename(r.get_method_frame()->caller()->junction.method)); + r.use_file(r.main_class, vfile.as_string(), r.get_method_filename(&r.get_method_frame()->caller()->method)); } static void set_skip(Request& r, Request::Skip askip) { if(!r.get_in_cycle()) - throw Exception(PARSER_RUNTIME, + throw Exception(askip==Request::SKIP_BREAK?"parser.break":"parser.continue", 0, "without cycle"); @@ -379,9 +378,6 @@ static void _eval(Request& r, MethodPara } static void _connect(Request& r, MethodParams& params) { -#ifdef RESOURCES_DEBUG -struct timeval mt[2]; -#endif Value& url=params.as_no_junction(0, "url must not be code"); Value& body_code=params.as_junction(1, "body must be code"); @@ -392,27 +388,14 @@ struct timeval mt[2]; } } -#ifdef RESOURCES_DEBUG -//measure:before -gettimeofday(&mt[0],NULL); -#endif // connect SQL_Connection* connection=SQL_driver_manager->get_connection(url.as_string(), protocol2driver_and_client, r.charsets.source().NAME().cstr(), r.request_info.document_root); -#ifdef RESOURCES_DEBUG -//measure:after connect -gettimeofday(&mt[1],NULL); - -double t[2]; -for(int i=0;i<2;i++) - t[i]=mt[i].tv_sec+mt[i].tv_usec/1000000.0; - -r.sql_connect_time+=t[1]-t[0]; -#endif Temp_connection temp_connection(r, connection); + // execute body try { r.process_write(body_code); @@ -431,6 +414,7 @@ public: Request& r; const String* searching_string; double searching_double; + bool searching_bool; Value* found; Value* _default; public: @@ -440,17 +424,18 @@ public: if(asearching.is_string() || asearching.is_void()){ searching_string=&asearching.as_string(); searching_double=0; + searching_bool=false; } else { searching_string=0; searching_double=asearching.as_double(); + searching_bool=asearching.is_bool(); } } }; #endif static void _switch(Request& r, MethodParams& params) { Switch_data* data=new Switch_data(r, r.process_to_value(params[0])); - Temp_hash_value - switch_data_setter(r.classes_conf, switch_data_name, data); + Temp_hash_value, void*> switch_data_setter(&r.classes_conf, switch_data_name, data); Value& cases_code=params.as_junction(1, "switch cases must be code"); // execution of found ^case[...]{code} must be in context of ^switch[...]{code} @@ -492,6 +477,8 @@ static void _case(Request& r, MethodPara bool matches; if(data->searching_string) matches=(*data->searching_string) == value.as_string(); + else if(data->searching_bool || value.is_bool()) + matches=(data->searching_double != 0) == value.as_bool(); else matches=data->searching_double == value.as_double(); @@ -759,8 +746,7 @@ static void _cache(Request& r, MethodPar Cache_scope scope={as_expires(r, params, 1, now), 0}; - Temp_hash_value - cache_scope_setter(r.classes_conf, cache_data_name, &scope); + Temp_hash_value, void*> cache_scope_setter(&r.classes_conf, cache_data_name, &scope); Value& body_code=params.as_junction(2, "body_code must be code"); Value* catch_code=0; if(params.count()>3) @@ -868,7 +854,8 @@ static void _throw_operator(Request&, Me static void _sleep_operator(Request& r, MethodParams& params) { double seconds=params.as_double(0, "seconds must be double", r); - pa_sleep((int)trunc(seconds), (int)trunc(seconds*1000)); + if(seconds>0) + pa_sleep((int)trunc(seconds), (int)trunc((seconds-trunc(seconds))*1000000)); } #if defined(WIN32) && defined(_DEBUG) @@ -899,6 +886,9 @@ VClassMAIN::VClassMAIN(): VClass() { // ^taint[as-is|uri|sql|js|html|html-typo|regex|parser-code]{code} add_native_method("taint", Method::CT_ANY, _taint, 1, 2, Method::CO_WITHOUT_FRAME); + // ^apply-taint[untaint lang][string] + add_native_method("apply-taint", Method::CT_ANY, _apply_taint, 1, 2, Method::CO_WITHOUT_FRAME); + // ^process[code] add_native_method("process", Method::CT_ANY, _process, 1, 3);