|
|
| version 1.162, 2007/11/14 12:46:02 | version 1.177, 2008/08/29 08:24:17 |
|---|---|
| Line 9 static const char * const IDENT_FILE_C=" | Line 9 static const char * const IDENT_FILE_C=" |
| #include "pa_config_includes.h" | #include "pa_config_includes.h" |
| #include "pcre.h" | |
| #include "classes.h" | #include "classes.h" |
| #include "pa_vmethod_frame.h" | #include "pa_vmethod_frame.h" |
| Line 232 static void _load(Request& r, MethodPara | Line 230 static void _load(Request& r, MethodPara |
| :lfile_name.cstr(String::L_FILE_SPEC); | :lfile_name.cstr(String::L_FILE_SPEC); |
| Value* vcontent_type=0; | Value* vcontent_type=0; |
| if(file.headers) | if(file.headers){ |
| { | |
| if(Value* remote_content_type=file.headers->get("CONTENT-TYPE")) | if(Value* remote_content_type=file.headers->get("CONTENT-TYPE")) |
| vcontent_type=new VString(*new String(remote_content_type->as_string().cstr())); | vcontent_type=new VString(*new String(remote_content_type->as_string().cstr())); |
| } | } |
| Line 242 static void _load(Request& r, MethodPara | Line 239 static void _load(Request& r, MethodPara |
| VFile& self=GET_SELF(r, VFile); | VFile& self=GET_SELF(r, VFile); |
| self.set(true/*tainted*/, file.str, file.length, user_file_name, vcontent_type); | self.set(true/*tainted*/, file.str, file.length, user_file_name, vcontent_type); |
| if(file.headers) | |
| if(file.headers){ | |
| file.headers->for_each<HashStringValue*>(_load_pass_param, &self.fields()); | file.headers->for_each<HashStringValue*>(_load_pass_param, &self.fields()); |
| } else { | |
| size_t size; | |
| time_t atime, mtime, ctime; | |
| file_stat(lfile_name, size, atime, mtime, ctime); | |
| HashStringValue& ff=self.fields(); | |
| ff.put(adate_name, new VDate(atime)); | |
| ff.put(mdate_name, new VDate(mtime)); | |
| ff.put(cdate_name, new VDate(ctime)); | |
| } | |
| } | } |
| static void _create(Request& r, MethodParams& params) { | static void _create(Request& r, MethodParams& params) { |
| Line 276 static void _stat(Request& r, MethodPara | Line 286 static void _stat(Request& r, MethodPara |
| size, | size, |
| atime, mtime, ctime); | atime, mtime, ctime); |
| const char* user_file_name=lfile_name.cstr(String::L_FILE_SPEC); | |
| VFile& self=GET_SELF(r, VFile); | VFile& self=GET_SELF(r, VFile); |
| self.set(true/*tainted*/, 0/*no bytes*/, size); | |
| self.set(true/*tainted*/, 0/*no bytes*/, size, user_file_name, new VString(r.mime_type_of(user_file_name))); | |
| HashStringValue& ff=self.fields(); | HashStringValue& ff=self.fields(); |
| ff.put(adate_name, new VDate(atime)); | ff.put(adate_name, new VDate(atime)); |
| ff.put(mdate_name, new VDate(mtime)); | ff.put(mdate_name, new VDate(mtime)); |
| ff.put(cdate_name, new VDate(ctime)); | ff.put(cdate_name, new VDate(ctime)); |
| ff.put(content_type_name, new VString(r.mime_type_of(lfile_name.cstr(String::L_FILE_SPEC)))); | |
| } | } |
| static bool is_safe_env_key(const char* key) { | static bool is_safe_env_key(const char* key) { |
| Line 351 static void append_to_argv(Request& r, A | Line 363 static void append_to_argv(Request& r, A |
| } | } |
| } | } |
| inline size_t strpos(const char *s1, const char *s2) { | |
| const char *p = strstr(s1, s2); | |
| return (p==0)?(size_t)-1:p-s1; | |
| } | |
| /// @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, MethodParams& params, | static void _exec_cgi(Request& r, MethodParams& params, |
| bool cgi) { | bool cgi) { |
| Line 488 static void _exec_cgi(Request& r, Method | Line 495 static void _exec_cgi(Request& r, Method |
| // match silent conversion in OS | // match silent conversion in OS |
| // exec! | // exec! |
| PA_exec_result execution= | PA_exec_result execution=pa_exec(false/*forced_allow*/, script_name, &env, argv, *in); |
| pa_exec(false/*forced_allow*/, script_name, &env, argv, *in); | |
| File_read_result *file_out=&execution.out; | File_read_result *file_out=&execution.out; |
| String *real_err=&execution.err; | String *real_err=&execution.err; |
| if(is_text_mode(mode_name)){ | // transcode err if necessary (@todo: need fix line breaks in err as well ) |
| if(charset) | |
| real_err=&Charset::transcode(*real_err, *charset, r.charsets.source()); | |
| if(file_out->length && is_text_mode(mode_name)){ | |
| fix_line_breaks(file_out->str, file_out->length); | fix_line_breaks(file_out->str, file_out->length); |
| // treat output as string | // treat output as string |
| String *real_out = new String(file_out->str, file_out->length); | String *real_out = new String(file_out->str, file_out->length); |
| // transcode if necessary | // transcode out if necessary |
| if(charset) { | if(charset) |
| real_out=&Charset::transcode(*real_out, *charset, r.charsets.source()); | real_out=&Charset::transcode(*real_out, *charset, r.charsets.source()); |
| real_err=&Charset::transcode(*real_err, *charset, r.charsets.source()); | |
| } | |
| // FIXME: unsafe cast | // FIXME: unsafe cast |
| file_out->str = (char*)real_out->cstr(); | file_out->str=const_cast<char *>(real_out->cstr()); // hacking a little |
| file_out->length = real_out->length(); | file_out->length = real_out->length(); |
| } | } |
| VFile& self=GET_SELF(r, VFile); | VFile& self=GET_SELF(r, VFile); |
| if(cgi) { // ^file::cgi | if(cgi) { // ^file::cgi |
| const char* eol_marker=0; size_t eol_marker_size; | const char* eol_marker=0; |
| size_t eol_marker_size; | |
| // construct with 'out' body and header | // construct with 'out' body and header |
| size_t dos_pos=strpos(file_out->str, "\r\n\r\n"); | size_t dos_pos=(file_out->length)?strpos(file_out->str, "\r\n\r\n"):STRING_NOT_FOUND; |
| size_t unix_pos=strpos(file_out->str, "\n\n"); | size_t unix_pos=(file_out->length)?strpos(file_out->str, "\n\n"):STRING_NOT_FOUND; |
| bool unix_header_break; | bool unix_header_break; |
| switch((dos_pos!=STRING_NOT_FOUND?10:00) + (unix_pos!=STRING_NOT_FOUND?01:00)) { | switch((dos_pos!=STRING_NOT_FOUND?10:00) + (unix_pos!=STRING_NOT_FOUND?01:00)) { |
| case 10: // dos | case 10: // dos |
| unix_header_break=false; | unix_header_break=false; |
| break; | break; |
| case 01: // unix | case 01: // unix |
| unix_header_break=true; | unix_header_break=true; |
| break; | break; |
| case 11: // dos & unix | case 11: // dos & unix |
| unix_header_break=unix_pos<dos_pos; | unix_header_break=unix_pos<dos_pos; |
| break; | break; |
| default: // 00 | default: // 00 |
| unix_header_break=false; // calm down, compiler | unix_header_break=false; // calm down, compiler |
| throw Exception(0, | throw Exception(0, |
| 0, | 0, |
| "output does not contain CGI header; " | "output does not contain CGI header; " |
| "exit status=%d; stdoutsize=%u; stdout: \"%s\"; stderrsize=%u; stderr: \"%s\"", | "exit status=%d; stdoutsize=%u; stdout: \"%s\"; stderrsize=%u; stderr: \"%s\"", |
| execution.status, | execution.status, |
| (uint)file_out->length, file_out->str, | (size_t)file_out->length, (file_out->length) ? (file_out->str) : "", |
| (uint)real_err->length(), real_err->cstr()); | (size_t)real_err->length(), real_err->cstr()); |
| break; //never reached | break; //never reached |
| } | } |
| int header_break_pos; | size_t header_break_pos; |
| if(unix_header_break) { | if(unix_header_break) { |
| header_break_pos=unix_pos; | header_break_pos=unix_pos; |
| eol_marker="\n"; eol_marker_size=1; | eol_marker="\n"; |
| eol_marker_size=1; | |
| } else { | } else { |
| header_break_pos=dos_pos; | header_break_pos=dos_pos; |
| eol_marker="\r\n"; eol_marker_size=2; | eol_marker="\r\n"; |
| eol_marker_size=2; | |
| } | } |
| file_out->str[header_break_pos] = 0; | file_out->str[header_break_pos] = 0; |
| Line 555 static void _exec_cgi(Request& r, Method | Line 568 static void _exec_cgi(Request& r, Method |
| file_out->str += headersize; | file_out->str += headersize; |
| file_out->length -= headersize; | file_out->length -= headersize; |
| // body | // $body |
| self.set(false/*not tainted*/, file_out->str, file_out->length); | self.set(false/*not tainted*/, file_out->str, file_out->length); |
| // $fields << header | // $fields << header |
| Line 570 static void _exec_cgi(Request& r, Method | Line 583 static void _exec_cgi(Request& r, Method |
| if(info.content_type) | if(info.content_type) |
| self.fields().put(content_type_name, info.content_type); | self.fields().put(content_type_name, info.content_type); |
| } | } |
| } else { | } else { // ^file::exec |
| // $body | |
| self.set(false/*not tainted*/, file_out->str, file_out->length); | self.set(false/*not tainted*/, file_out->str, file_out->length); |
| } | } |
| Line 600 static void _list(Request& r, MethodPara | Line 614 static void _list(Request& r, MethodPara |
| if(params.count()>1) { | if(params.count()>1) { |
| regexp=¶ms.as_no_junction(1, "regexp must not be code").as_string(); | regexp=¶ms.as_no_junction(1, "regexp must not be code").as_string(); |
| const char* pattern=regexp->cstr(); | const char* pattern=regexp->cstr(String::L_UNSPECIFIED); |
| const char* errptr; | const char* errptr; |
| int erroffset; | int erroffset; |
| regexp_code=pcre_compile(pattern, PCRE_EXTRA | PCRE_DOTALL, | int options=PCRE_EXTRA | PCRE_DOTALL; |
| if(r.charsets.source().isUTF8()) | |
| options=options|PCRE_UTF8; | |
| regexp_code=pcre_compile(pattern, options, | |
| &errptr, &erroffset, | &errptr, &erroffset, |
| r.charsets.source().pcre_tables); | r.charsets.source().pcre_tables); |
| Line 637 static void _list(Request& r, MethodPara | Line 655 static void _list(Request& r, MethodPara |
| else if(exec_result<0) { | else if(exec_result<0) { |
| (*pcre_free)(regexp_code); | (*pcre_free)(regexp_code); |
| throw Exception(0, | throw Exception(0, |
| regexp, | regexp, |
| "regular expression execute (%d)", | print_pcre_exec_error_text(exec_result), |
| exec_result); | exec_result); |
| } | } |
| } | } |
| Line 856 static void _sql(Request& r, MethodParam | Line 874 static void _sql(Request& r, MethodParam |
| statement_string.cstr(String::L_UNSPECIFIED, r.connection()); | statement_string.cstr(String::L_UNSPECIFIED, r.connection()); |
| File_sql_event_handlers handlers(statement_string, statement_cstr); | File_sql_event_handlers handlers(statement_string, statement_cstr); |
| ulong limit=SQL_NO_LIMIT; | |
| ulong offset=0; | |
| if(params.count()>1) | if(params.count()>1) |
| if(HashStringValue* options= | if(HashStringValue* options=params.as_no_junction(1, PARAM_MUST_NOT_BE_CODE).get_hash()){ |
| params.as_no_junction(1, PARAM_MUST_NOT_BE_CODE).get_hash()) { | |
| int valid_options=0; | int valid_options=0; |
| if(Value* vfilename=options->get(NAME_NAME)) { | if(Value* vfilename=options->get(NAME_NAME)) { |
| valid_options++; | valid_options++; |
| Line 868 static void _sql(Request& r, MethodParam | Line 888 static void _sql(Request& r, MethodParam |
| valid_options++; | valid_options++; |
| handlers.user_content_type=&vcontent_type->as_string(); | handlers.user_content_type=&vcontent_type->as_string(); |
| } | } |
| if(Value* vlimit=options->get(sql_limit_name)) { | |
| valid_options++; | |
| limit=(ulong)r.process_to_value(*vlimit).as_double(); | |
| } | |
| if(Value* voffset=options->get(sql_offset_name)) { | |
| valid_options++; | |
| offset=(ulong)r.process_to_value(*voffset).as_double(); | |
| } | |
| if(valid_options!=options->count()) | if(valid_options!=options->count()) |
| throw Exception(PARSER_RUNTIME, | throw Exception(PARSER_RUNTIME, |
| 0, | 0, |
| Line 878 static void _sql(Request& r, MethodParam | Line 906 static void _sql(Request& r, MethodParam |
| r.connection()->query( | r.connection()->query( |
| statement_cstr, | statement_cstr, |
| 0, 0, | 0, 0, |
| 0, 0, | offset, limit, |
| handlers, | handlers, |
| statement_string); | statement_string); |