|
|
| version 1.88.2.1, 2002/06/20 16:31:07 | version 1.92, 2002/08/01 11:41:12 |
|---|---|
| Line 3 | Line 3 |
| Copyright (c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com) | Copyright (c) 2001, 2002 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) |
| $Id$ | |
| */ | */ |
| static const char* IDENT_FILE_C="$Date$"; | |
| #include "pa_config_includes.h" | #include "pa_config_includes.h" |
| #include "pcre.h" | #include "pcre.h" |
| Line 25 | Line 25 |
| // defines | // defines |
| #define TEXT_MODE_NAME "text" | #define TEXT_MODE_NAME "text" |
| #define STDIN_EXEC_PARAM_NAME "stdin" | |
| // consts | // consts |
| Line 87 public: | Line 88 public: |
| }; | }; |
| // consts | |
| const int FIND_MONKEY_MAX_HOPS=10; | |
| // methods | // methods |
| static void _save(Request& r, const String&, MethodParams *params) { | static void _save(Request& r, const String&, MethodParams *params) { |
| Line 119 static void _move(Request& r, const Stri | Line 116 static void _move(Request& r, const Stri |
| r.absolute(vto_file_name.as_string())); | r.absolute(vto_file_name.as_string())); |
| } | } |
| static void _find(Request& r, const String& method_name, MethodParams *params) { | |
| Pool& pool=r.pool(); | |
| Value& vfile_name=params->as_no_junction(0, "file name must not be code"); | |
| const String &lfile_name=vfile_name.as_string(); | |
| // passed file name simply exists in current dir | |
| if(file_readable(r.absolute(lfile_name))) { | |
| r.write_no_lang(lfile_name); | |
| return; | |
| } | |
| // scan .. dirs for result | |
| for(int i=0; i<FIND_MONKEY_MAX_HOPS; i++) { | |
| String local_test_name(pool); | |
| for(int j=0; j<i; j++) | |
| local_test_name.APPEND_CONST("../"); | |
| local_test_name.append(lfile_name, String::UL_CLEAN); | |
| if(file_readable(r.absolute(local_test_name))) { | |
| r.write_no_lang(*new(pool) String(local_test_name)); | |
| return; | |
| } | |
| } | |
| // not found | |
| if(params->size()==2) { | |
| Value& not_found_code=params->as_junction(1, "not-found param must be code"); | |
| r.write_pass_lang(r.process(not_found_code)); | |
| } | |
| } | |
| static void _load(Request& r, const String& method_name, MethodParams *params) { | static void _load(Request& r, const String& method_name, MethodParams *params) { |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| Value& vmode_name=params-> as_no_junction(0, "mode must not be code"); | Value& vmode_name=params-> as_no_junction(0, "mode must not be code"); |
| Line 200 static bool is_safe_env_key(const char * | Line 166 static bool is_safe_env_key(const char * |
| } | } |
| return false; | return false; |
| } | } |
| #ifndef DOXYGEN | |
| struct Append_env_pair_info { | |
| Hash* hash; | |
| const String* sstdin; | |
| }; | |
| #endif | |
| static void append_env_pair(const Hash::Key& key, Hash::Val *value, void *info) { | static void append_env_pair(const Hash::Key& key, Hash::Val *value, void *info) { |
| Hash& hash=*static_cast<Hash *>(info); | Append_env_pair_info& pi=*static_cast<Append_env_pair_info *>(info); |
| if(!is_safe_env_key(key.cstr())) | const String& svalue=static_cast<Value *>(value)->as_string(); |
| throw Exception("parser.runtime", | |
| &key, | if(key==STDIN_EXEC_PARAM_NAME) { |
| "not safe environment variable"); | pi.sstdin=&svalue; |
| hash.put(key, &static_cast<Value *>(value)->as_string()); | } else { |
| if(!is_safe_env_key(key.cstr())) | |
| throw Exception("parser.runtime", | |
| &key, | |
| "not safe environment variable"); | |
| pi.hash->put(key, &svalue); | |
| } | |
| } | } |
| static void pass_cgi_header_attribute(Array::Item *value, void *info) { | static void pass_cgi_header_attribute(Array::Item *value, void *info) { |
| String& string=*static_cast<String *>(value); | String& string=*static_cast<String *>(value); |
| Line 216 static void pass_cgi_header_attribute(Ar | Line 194 static void pass_cgi_header_attribute(Ar |
| hash.put(string.mid(0, colon_pos), | hash.put(string.mid(0, colon_pos), |
| new(string.pool()) VString(string.mid(colon_pos+1, string.size()))); | new(string.pool()) VString(string.mid(colon_pos+1, string.size()))); |
| } | } |
| /** @todo fix `` in perl - they produced flipping consoles and no output to perl | /// @todo fix `` in perl - they produced flipping consoles and no output to perl |
| */ | |
| static void _exec_cgi(Request& r, const String& method_name, MethodParams *params, | static void _exec_cgi(Request& r, const String& method_name, MethodParams *params, |
| bool cgi) { | bool cgi) { |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| Line 261 static void _exec_cgi(Request& r, const | Line 238 static void _exec_cgi(Request& r, const |
| env.put(*new(pool) String(pool, "SCRIPT_NAME"), &script_name); | env.put(*new(pool) String(pool, "SCRIPT_NAME"), &script_name); |
| //env.put(*new(pool) String(pool, "SCRIPT_FILENAME"), ??&script_name); | //env.put(*new(pool) String(pool, "SCRIPT_FILENAME"), ??&script_name); |
| // environment & stdin from param | |
| String in(pool); | |
| if(params->size()>1) { | if(params->size()>1) { |
| Value& venv=params->as_no_junction(1, "env must not be code"); | Value& venv=params->as_no_junction(1, "env must not be code"); |
| if(Hash *user_env=venv.get_hash(&method_name)) | if(Hash *user_env=venv.get_hash(&method_name)) { |
| user_env->for_each(append_env_pair, &env); | Append_env_pair_info info={&env}; |
| user_env->for_each(append_env_pair, &info); | |
| if(info.sstdin) | |
| in.append(*info.sstdin, String::UL_CLEAN, true); | |
| } | |
| } | } |
| // argv from params | |
| Array *argv=0; | Array *argv=0; |
| if(params->size()>2) { | if(params->size()>2) { |
| argv=new(pool) Array(pool, params->size()-2); | argv=new(pool) Array(pool, params->size()-2); |
| Line 274 static void _exec_cgi(Request& r, const | Line 258 static void _exec_cgi(Request& r, const |
| *argv+=¶ms->as_string(i, "parameter must be string"); | *argv+=¶ms->as_string(i, "parameter must be string"); |
| } | } |
| String in(pool); | // passing POST data |
| in.APPEND(r.post_data, r.post_size, String::UL_CLEAN, "passing post data", 0); | if(in.is_empty()) // if $.stdin[...] not specified |
| in.APPEND(r.post_data, r.post_size, String::UL_CLEAN, "POST data (passed)", 0); | |
| // exec! | |
| String out(pool); | String out(pool); |
| //out.APPEND_CONST("content-type:text/plain\nheader:test-header\n\ntest-body"); | |
| //out<<in; | |
| String& err=*new(pool) String(pool); | String& err=*new(pool) String(pool); |
| int status=pa_exec(false/*forced_allow*/, script_name, &env, argv, in, out, err); | int status=pa_exec(false/*forced_allow*/, script_name, &env, argv, in, out, err); |
| Line 298 static void _exec_cgi(Request& r, const | Line 283 static void _exec_cgi(Request& r, const |
| delim_size=0; // calm down, compiler | delim_size=0; // calm down, compiler |
| throw Exception(0, | throw Exception(0, |
| &method_name, | &method_name, |
| "output does not contain CGI header; exit status=%d; stdoutsize=%u; stdout: \"%s\"; stderrsize=%u; stderr: \"%s\"", | "output does not contain CGI header; " |
| "exit status=%d; stdoutsize=%u; stdout: \"%s\"; stderrsize=%u; stderr: \"%s\"", | |
| status, | status, |
| (uint)out.size(), out.cstr(), | (uint)out.size(), out.cstr(), |
| (uint)err.size(), err.cstr()); | (uint)err.size(), err.cstr()); |
| Line 447 static int lastposafter(const String& s, | Line 433 static int lastposafter(const String& s, |
| return after; | return after; |
| } | } |
| static void _find(Request& r, const String& method_name, MethodParams *params) { | |
| Pool& pool=r.pool(); | |
| const String &file_name=params->as_no_junction(0, "file name must not be code").as_string(); | |
| const String *file_spec; | |
| if(file_name.first_char()=='/') | |
| file_spec=&file_name; | |
| else | |
| file_spec=&r.relative(r.info.uri, file_name); | |
| // easy way | |
| if(file_readable(r.absolute(*file_spec))) { | |
| r.write_no_lang(*file_spec); | |
| return; | |
| } | |
| // monkey way | |
| int after_base_slash=lastposafter(*file_spec, 0, "/", 1); | |
| const String *dirname=&file_spec->mid(0, after_base_slash); | |
| const String& basename=file_spec->mid(after_base_slash, file_spec->size()); | |
| int after_monkey_slash; | |
| while((after_monkey_slash=lastposafter(*dirname, 0, "/", 1, true))>0) { | |
| String local_test_name(pool); | |
| local_test_name<<*(dirname=&dirname->mid(0, after_monkey_slash)); | |
| local_test_name<<basename; | |
| if(file_readable(r.absolute(local_test_name))) { | |
| r.write_no_lang(*new(pool) String(local_test_name)); | |
| return; | |
| } | |
| } | |
| // no way, not found | |
| if(params->size()==2) { | |
| Value& not_found_code=params->as_junction(1, "not-found param must be code"); | |
| r.write_pass_lang(r.process(not_found_code)); | |
| } | |
| } | |
| static void _dirname(Request& r, const String& method_name, MethodParams *params) { | static void _dirname(Request& r, const String& method_name, MethodParams *params) { |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| const String& file_spec=params->as_string(0, "file name must be string"); | const String& file_spec=params->as_string(0, "file name must be string"); |
| Line 494 MFile::MFile(Pool& apool) : Methoded(apo | Line 518 MFile::MFile(Pool& apool) : Methoded(apo |
| // ^move[from-file-name;to-file-name] | // ^move[from-file-name;to-file-name] |
| add_native_method("move", Method::CT_STATIC, _move, 2, 2); | add_native_method("move", Method::CT_STATIC, _move, 2, 2); |
| // ^find[file-name] | |
| // ^find[file-name]{when-not-found} | |
| add_native_method("find", Method::CT_STATIC, _find, 1, 2); | |
| // ^load[mode;disk-name] | // ^load[mode;disk-name] |
| // ^load[mode;disk-name;user-name] | // ^load[mode;disk-name;user-name] |
| add_native_method("load", Method::CT_DYNAMIC, _load, 2, 3); | add_native_method("load", Method::CT_DYNAMIC, _load, 2, 3); |
| Line 522 MFile::MFile(Pool& apool) : Methoded(apo | Line 542 MFile::MFile(Pool& apool) : Methoded(apo |
| // ^file:lock[path]{code} | // ^file:lock[path]{code} |
| add_native_method("lock", Method::CT_STATIC, _lock, 2, 2); | add_native_method("lock", Method::CT_STATIC, _lock, 2, 2); |
| // ^find[file-name] | |
| // ^find[file-name]{when-not-found} | |
| add_native_method("find", Method::CT_STATIC, _find, 1, 2); | |
| // ^file:dirname[/a/some.tar.gz]=/a | // ^file:dirname[/a/some.tar.gz]=/a |
| // ^file:dirname[/a/b/]=/a | // ^file:dirname[/a/b/]=/a |
| add_native_method("dirname", Method::CT_STATIC, _dirname, 1, 1); | add_native_method("dirname", Method::CT_STATIC, _dirname, 1, 1); |