Diff for /parser3/src/classes/file.C between versions 1.88.2.1 and 1.96

version 1.88.2.1, 2002/06/20 16:31:07 version 1.96, 2002/08/20 14:20:36
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");
         Value& vfile_name=params->as_no_junction(1, "file name must not be code");          const String& lfile_name=r.absolute(params->as_no_junction(1, "file name must not be code").as_string());
   
         const String& lfile_name=vfile_name.as_string();  
   
         void *data;  size_t size;          void *data;  size_t size;
         file_read(pool, r.absolute(lfile_name), data, size,           file_read(pool, lfile_name, data, size, 
                 vmode_name.as_string()==TEXT_MODE_NAME);                  vmode_name.as_string()==TEXT_MODE_NAME);
   
         char *user_file_name=params->size()>2?          char *user_file_name=params->size()>2?
Line 187  static void _stat(Request& r, const Stri Line 151  static void _stat(Request& r, const Stri
         ff.put(*new(pool) String(pool, "adate"), new(pool) VDate(pool, atime));          ff.put(*new(pool) String(pool, "adate"), new(pool) VDate(pool, atime));
         ff.put(*new(pool) String(pool, "mdate"), new(pool) VDate(pool, mtime));          ff.put(*new(pool) String(pool, "mdate"), new(pool) VDate(pool, mtime));
         ff.put(*new(pool) String(pool, "cdate"), new(pool) VDate(pool, ctime));          ff.put(*new(pool) String(pool, "cdate"), new(pool) VDate(pool, ctime));
           ff.put(*content_type_name, new(pool) VString(r.mime_type_of(lfile_name.cstr(String::UL_FILE_SPEC))));
 }  }
   
 static bool is_safe_env_key(const char *key) {  static bool is_safe_env_key(const char *key) {
Line 200  static bool is_safe_env_key(const char * Line 165  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) {  #ifndef DOXYGEN
   struct Pass_cgi_header_attribute_info {
           Hash *hash;
           Value *content_type;
   };
   #endif
   static void pass_cgi_header_attribute(Array::Item *value, void *ainfo) {
         String& string=*static_cast<String *>(value);          String& string=*static_cast<String *>(value);
         Hash& hash=*static_cast<Hash *>(info);          Pool& pool=string.pool();
           Pass_cgi_header_attribute_info& info=*static_cast<Pass_cgi_header_attribute_info *>(ainfo);
         int colon_pos=string.pos(":", 1);          int colon_pos=string.pos(":", 1);
         if(colon_pos>0)          if(colon_pos>0) {
                 hash.put(string.mid(0, colon_pos),                   const String& key=string.mid(0, colon_pos).change_case(pool, String::CC_UPPER);
                 new(string.pool()) VString(string.mid(colon_pos+1, string.size())));                  Value *value=new(pool) VString(string.mid(colon_pos+1, string.size()));
                   info.hash->put(key, value);
                   if(key=="CONTENT-TYPE")
                           info.content_type=value;
           }
 }  }
 /** @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 248  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 268  static void _exec_cgi(Request& r, const
                         *argv+=&params->as_string(i, "parameter must be string");                          *argv+=&params->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);
   
         VFile& self=*static_cast<VFile *>(r.self);          VFile& self=*static_cast<VFile *>(r.self);
   
         const String *body=&out; // ^file:exec          const String *body=&out; // ^file:exec
           Value *content_type=0;
           const char *eol_marker="\r\n"; size_t eol_marker_size=2;
           const String *header=0;
         if(cgi) { // ^file:cgi          if(cgi) { // ^file:cgi
                 // construct with 'out' body and header                  // construct with 'out' body and header
                 int delim_size;                  int delim_size;
                 const char *eol_marker="\r\n"; size_t eol_marker_size=2;  
                 int pos=out.pos("\r\n\r\n", delim_size=4);                  int pos=out.pos("\r\n\r\n", delim_size=4);
                 if(pos<0) {                  if(pos<0) {
                         eol_marker="\n"; eol_marker_size=1;                          eol_marker="\n"; eol_marker_size=1;
Line 298  static void _exec_cgi(Request& r, const Line 295  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());
                 }                  }
   
                 const String& header=out.mid(0, pos);                  header=&out.mid(0, pos);
                 body=&out.mid(pos+delim_size, out.size());                  body=&out.mid(pos+delim_size, out.size());
   
                 // header to $fields  
                 {  
                         Array rows(pool);  
                         header.split(rows, 0, eol_marker, eol_marker_size, String::UL_CLEAN);  
                         rows.for_each(pass_cgi_header_attribute, &self.fields());  
                 }  
         }          }
         // body          // body
         self.set(false/*not tainted*/, body->cstr(), body->size());          self.set(false/*not tainted*/, body->cstr(), body->size());
   
           // $fields << header
           if(header) {
                   Array rows(pool);
                   header->split(rows, 0, eol_marker, eol_marker_size);
                   Pass_cgi_header_attribute_info info={&self.fields()};
                   rows.for_each(pass_cgi_header_attribute, &info);
                   if(info.content_type)
                           self.fields().put(*content_type_name, info.content_type);
           }
   
         // $status          // $status
         self.fields().put(          self.fields().put(
                 *new(pool) String(pool, "status"),                  *new(pool) String(pool, "status"),
Line 447  static int lastposafter(const String& s, Line 448  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_assign_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_assign_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 533  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 557  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);

Removed from v.1.88.2.1  
changed lines
  Added in v.1.96


E-mail: