--- parser3/src/classes/file.C 2004/12/23 15:36:12 1.131 +++ parser3/src/classes/file.C 2005/11/24 14:00:34 1.142 @@ -1,11 +1,11 @@ /** @file Parser: @b file parser class. - Copyright (c) 2001-2004 ArtLebedev Group (http://www.artlebedev.com) + Copyright (c) 2001-2005 ArtLebedev Group (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) */ -static const char * const IDENT_FILE_C="$Date: 2004/12/23 15:36:12 $"; +static const char * const IDENT_FILE_C="$Date: 2005/11/24 14:00:34 $"; #include "pa_config_includes.h" @@ -35,12 +35,17 @@ static const char * const IDENT_FILE_C=" #define NAME_NAME "name" +// externs + +extern String sql_limit_name; +extern String sql_offset_name; + // class class MFile: public Methoded { public: // VStateless_class - Value* create_new_value(Pool&) { return new VFile(); } + Value* create_new_value(Pool&, HashStringValue&) { return new VFile(); } public: // Methoded bool used_directly() { return true; } @@ -160,9 +165,22 @@ static void _load(Request& r, MethodPara if(third_param_hash) alt_filename_param_index++; + HashStringValue* options=third_param_hash; + size_t offset=0; + size_t limit=0; + if(options) { + options=new HashStringValue(*options); + if(Value *voffset=(Value *)options->get(sql_offset_name)) { + offset=r.process_to_value(*voffset).as_int(); + } + if(Value *vlimit=(Value *)options->get(sql_limit_name)) { + limit=r.process_to_value(*vlimit).as_int(); + } + // no check on options count here, see file_read + } File_read_result file=file_read(r.charsets, lfile_name, is_text_mode(vmode_name.as_string()), - third_param_hash + options, true, 0, offset, limit ); const char *user_file_name=params.count()>alt_filename_param_index? @@ -184,6 +202,25 @@ static void _load(Request& r, MethodPara file.headers->for_each(_load_pass_param, &self.fields()); } +static void _create(Request& r, MethodParams& params) { + Value& vmode_name=params. as_no_junction(0, "mode must not be code"); + if(!is_text_mode(vmode_name.as_string())) + throw Exception("parser.runtime", + 0, + "only text mode is currently supported"); + + const char* user_file_name_cstr=r.absolute( + params.as_no_junction(1, "file name must not be code").as_string()).cstr(String::L_FILE_SPEC); + + const String& content=params.as_string(2, "content must be string"); + const char* content_cstr=content.cstr(String::L_UNSPECIFIED); // explode content, honor tainting changes + + VString* vcontent_type=new VString(r.mime_type_of(user_file_name_cstr)); + + VFile& self=GET_SELF(r, VFile); + self.set(true/*tainted*/, content_cstr, strlen(content_cstr), user_file_name_cstr, vcontent_type); +} + static void _stat(Request& r, MethodParams& params) { Value& vfile_name=params.as_no_junction(0, "file name must not be code"); @@ -222,9 +259,9 @@ static bool is_safe_env_key(const char* } #ifndef DOXYGEN struct Append_env_pair_info { + Request_charsets* charsets; HashStringString* env; Value* vstdin; - Value* vcharset; }; #endif static void append_env_pair( @@ -234,13 +271,13 @@ static void append_env_pair( if(akey==STDIN_EXEC_PARAM_NAME) { info->vstdin=avalue; } else if(akey==CHARSET_EXEC_PARAM_NAME) { - info->vcharset=avalue; + // ignore, already processed } else { if(!is_safe_env_key(akey.cstr())) throw Exception("parser.runtime", new String(akey, String::L_TAINTED), "not safe environment variable"); - info->env->put(akey, avalue->as_string().cstr(String::L_UNSPECIFIED)); + info->env->put(akey, avalue->as_string().cstr_to_string_body(String::L_UNSPECIFIED, 0, info->charsets)); } } #ifndef DOXYGEN @@ -311,8 +348,19 @@ static void _exec_cgi(Request& r, Method if(params.count()>1) { Value& venv=params.as_no_junction(1, "env must not be code"); if(HashStringValue* user_env=venv.get_hash()) { - Append_env_pair_info info={&env, 0, 0}; - user_env->for_each(append_env_pair, &info); + // $.charset [previewing to handle URI pieces] + if(Value* vcharset=user_env->get(CHARSET_EXEC_PARAM_NAME)) + charset=&charsets.get(vcharset->as_string() + .change_case(r.charsets.source(), String::CC_UPPER)); + + // $.others + Append_env_pair_info info={&r.charsets, &env, 0}; + { + // influence URLencoding of tainted pieces to String::L_URI lang + // main target -- $.QUERY_STRING + Temp_client_charset temp(r.charsets, charset? *charset: r.charsets.source()); + user_env->for_each(append_env_pair, &info); + } // $.stdin if(info.vstdin) { stdin_specified=true; @@ -326,10 +374,6 @@ static void _exec_cgi(Request& r, Method 0, STDIN_EXEC_PARAM_NAME " parameter must be string or file"); } - // $.charset - if(info.vcharset) - charset=&charsets.get(info.vcharset->as_string() - .change_case(r.charsets.source(), String::CC_UPPER)); } } @@ -551,7 +595,7 @@ static void _find(Request& r, MethodPara file_spec=&r.relative(r.request_info.uri, file_name); // easy way - if(file_readable(r.absolute(*file_spec))) { + if(file_exist(r.absolute(*file_spec))) { r.write_assign_lang(*file_spec); return; } @@ -566,7 +610,7 @@ static void _find(Request& r, MethodPara String test_name; test_name<<*(dirname=&dirname->mid(0, after_monkey_slash)); test_name<