Diff for /parser3/src/classes/file.C between versions 1.17 and 1.31.2.2

version 1.17, 2001/04/03 08:23:05 version 1.31.2.2, 2001/04/27 16:48:19
Line 8 Line 8
         $Id$          $Id$
 */  */
   
   #include "classes.h"
 #include "pa_request.h"  #include "pa_request.h"
 #include "_file.h"  
 #include "pa_vfile.h"  #include "pa_vfile.h"
 #include "pa_table.h"  #include "pa_table.h"
   #include "pa_vint.h"
   #include "pa_exec.h"
   
 // consts  // defines
   
 const int FIND_MONKEY_MAX_HOPS=10;  #define FILE_CLASS_NAME "file"
   
   // class
   
 // global var  class MFile : public Methoded {
   public:
           MFile(Pool& pool);
           bool used_directly() { return true; }
   };
   
 VStateless_class *file_class;  // consts
   
   const int FIND_MONKEY_MAX_HOPS=10;
   
 // methods  // methods
   
 static void _save(Request& r, const String& method_name, Array *params) {  static void _save(Request& r, const String&, MethodParams *params) {
         Pool& pool=r.pool();          Value& vfile_name=params->get_no_junction(0, "file name must not be code");
         Value& vfile_name=*static_cast<Value *>(params->get(0));  
         // forcing  
         // ^save[this body type]  
         r.fail_if_junction_(true, vfile_name,   
                 method_name, "file name must not be junction");  
   
         // forcing untaint language  
         String lfile_name(pool);  
         lfile_name.append(vfile_name.as_string(),  
                 String::UL_FILE_NAME, true);  
   
         // save          // save
         static_cast<VFile *>(r.self)->save(r.absolute(lfile_name));          static_cast<VFile *>(r.self)->save(r.absolute(vfile_name.as_string()));
 }  }
   
 static void _delete(Request& r, const String& method_name, Array *params) {  static void _delete(Request& r, const String&, MethodParams *params) {
         Pool& pool=r.pool();          Pool& pool=r.pool();
         Value& vfile_name=*static_cast<Value *>(params->get(0));          Value& vfile_name=params->get_no_junction(0, "file name must not be code");
         // forcing  
         // ^delete[this body type]  
         r.fail_if_junction_(true, vfile_name,   
                 method_name, "file name must not be junction");  
   
         // forcing untaint language  
         String lfile_name(pool);  
         lfile_name.append(vfile_name.as_string(),  
                 String::UL_FILE_NAME, true);  
                   
         // unlink          // unlink
         file_delete(pool, r.absolute(lfile_name));          file_delete(pool, r.absolute(vfile_name.as_string()));
 }  }
   
 static void _find(Request& r, const String& method_name, Array *params) {  static void _find(Request& r, const String& method_name, MethodParams *params) {
         Pool& pool=r.pool();          Pool& pool=r.pool();
         Value& vfile_name=*static_cast<Value *>(params->get(0));          Value& vfile_name=params->get_no_junction(0, "file name must not be code");
         // forcing  
         // ^delete[this body type]          const String &lfile_name=vfile_name.as_string();
         r.fail_if_junction_(true, vfile_name,   
                 method_name, "file name must not be junction");  
   
         // forcing untaint language  
         String lfile_name(pool);  
         lfile_name.append(vfile_name.as_string(),  
                 String::UL_FILE_NAME, true);  
   
         // passed file name simply exists in current dir          // passed file name simply exists in current dir
         if(file_readable(r.absolute(lfile_name))) {          if(file_readable(r.absolute(lfile_name))) {
Line 90  static void _find(Request& r, const Stri Line 74  static void _find(Request& r, const Stri
   
         // not found          // not found
         if(params->size()==2) {          if(params->size()==2) {
                 // forcing ..{this body type}                  Value& not_found_code=params->get_junction(1, "not-found param must be code");
                 Value& not_found_code=*static_cast<Value *>(params->get(1));  
                 r.fail_if_junction_(false, not_found_code,   
                         method_name, "not-found param must be junction");  
                 r.write_pass_lang(r.process(not_found_code));                  r.write_pass_lang(r.process(not_found_code));
         }          }
 }  }
   
 static void _load(Request& r, const String& method_name, Array *params) {  static void _load(Request& r, const String& method_name, MethodParams *params) {
         Pool& pool=r.pool();          Pool& pool=r.pool();
         Value& vfile_name=*static_cast<Value *>(params->get(0));          Value& vfile_name=params->get_no_junction(0, "file name must not be code");
   
         // forcing ^load[this body type]          const String& lfile_name=vfile_name.as_string();
         r.fail_if_junction_(true, vfile_name,   
                 method_name, "file name must not be junction");  
   
         // forcing untaint language  
         String lfile_name(pool);  
         lfile_name.append(vfile_name.as_string(),  
                 String::UL_FILE_NAME, true);  
   
         void *data;  size_t size;          void *data;  size_t size;
         file_read(pool, r.absolute(lfile_name), data, size, false/*binary*/);          file_read(pool, r.absolute(lfile_name), data, size, false/*binary*/);
   
         char *user_file_name=params->size()==1?lfile_name.cstr()          char *user_file_name=params->size()==1?lfile_name.cstr(String::UL_FILE_NAME)
                 :static_cast<Value *>(params->get(1))->as_string().cstr();                  :params->get(1).as_string().cstr();
           
           static_cast<VFile *>(r.self)->set(true/*tainted*/, data, size, 
                   user_file_name, &r.mime_type_of(user_file_name));
   }
   
   static void _stat(Request& r, const String& method_name, MethodParams *params) {
           Pool& pool=r.pool();
           Value& vfile_name=params->get_no_junction(0, "file name must not be code");
   
           const String& lfile_name=vfile_name.as_string();
   
           size_t size=file_size(r.absolute(lfile_name));
                   
         const String *mime_type=0;          static_cast<VFile *>(r.self)->set(true/*tainted*/, 0/*no bytes*/, size);
         if(params->size()==3)  }
                 mime_type=&static_cast<Value *>(params->get(2))->as_string();  
         else {  static void append_env_pair(const Hash::Key& key, Hash::Val *value, void *info) {
                 if(r.mime_types) {          Hash& hash=*static_cast<Hash *>(info);
                         if(char *cext=strrchr(user_file_name, '.')) {          hash.put(key, &static_cast<Value *>(value)->as_string());
                                 cext++;  }
                                 String sext(pool, cext);  
                                 if(r.mime_types->locate(0, sext))  static void pass_cgi_header_attribute(Array::Item *value, void *info) {
                                         if(!(mime_type=r.mime_types->item(1)))          String& string=*static_cast<String *>(value);
                                                 PTHROW(0, 0,          Hash& hash=*static_cast<Hash *>(info);
                                                 r.mime_types->origin_string(),          int colon_pos=string.pos(":", 1);
                                                 "MIME-TYPE table column elements must not be empty");          if(colon_pos>0)
                         }                  hash.put(string.mid(0, colon_pos), 
                   new(string.pool()) VString(string.mid(colon_pos+1, string.size())));
   }
   /**
           ^exec[file-name]
           ^exec[file-name;env hash]
           ^exec[file-name;env hash;cmd;line;arg;s]
           @todo fix `` in perl - they produced flipping consoles and no output to perl
   */
   static void _cgi(Request& r, const String& method_name, MethodParams *params) {
           Pool& pool=r.pool();
   
           Value& vfile_name=params->get_no_junction(0, "file name must not be code");
   
           const String& script_name=r.absolute(vfile_name.as_string());
   
           Hash env(pool);
           #define PASS(key) \
                   String key(pool); \
                   if(const char *value=SAPI::get_env(pool, #key)) { \
                           key.APPEND_CONST(value); \
                           env.put(String(pool, #key), &key); \
                   }
           #define INFO(key, value) \
                   String value(pool); \
                   if(r.info.value) { \
                           value.APPEND_CONST(r.info.value); \
                           env.put(String(pool, key), &value); \
                 }                  }
   
           // const
           String gateway_interface(pool, "CGI/1.1");
           env.put(String(pool, "GATEWAY_INTERFACE"), &gateway_interface);
           // from Request.info
           INFO("DOCUMENT_ROOT", document_root);
           INFO("PATH_TRANSLATED", path_translated);
           INFO("SERVER_PROTOCOL", method);
           INFO("QUERY_STRING", query_string);
           INFO("REQUEST_URI", uri);
           INFO("CONTENT_TYPE", content_type);
           char content_length_cstr[MAX_NUMBER];  
           snprintf(content_length_cstr, MAX_NUMBER, "%u", r.info.content_length);
           String content_length(pool, content_length_cstr);
           env.put(String(pool, "CONTENT_LENGTH"), &content_length);
           INFO("HTTP_COOKIE", cookie);
           INFO("HTTP_USER_AGENT", user_agent);
           // passing some SAPI:get_env-s
           PASS(SERVER_NAME);
           PASS(SERVER_PORT);
           PASS(HTTP_REFERER);
           PASS(REMOTE_ADDR);
           PASS(REMOTE_HOST);
           PASS(REMOTE_USER);
           // SCRIPT_NAME
           env.put(String(pool, "SCRIPT_NAME"), &script_name);
   #ifdef WIN32
           // WIN32 shell
           PASS(COMSPEC);
   #endif
   
           if(params->size()>1) {
                   Value& venv=params->get_no_junction(1, "env must not be code");
                   if(Hash *user_env=venv.get_hash())
                           user_env->for_each(append_env_pair, &env);
                   else
                           PTHROW(0, 0,
                                   &method_name,
                                   "env must be hash");
           }
   
           Array *argv=0;
           if(params->size()>2) {
                   argv=new(pool) Array(pool, params->size()-2);
                   for(int i=2; i<params->size(); i++)
                           *argv+=&params->get(i).as_string();
           }
   
           const String in(pool, r.post_data, r.post_size);
           String out(pool);
           //out.APPEND_CONST("content-type:text/plain\nheader:test-header\n\ntest-body");
           //out<<in;
           String& err=*new(pool) String(pool);
           int exit_code=pa_exec(script_name, &env, argv, in, out, err);
   
           VFile& self=*static_cast<VFile *>(r.self);
           // construct with 'out' body and header
           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);
           if(pos<0) {
                   eol_marker="\n"; eol_marker_size=1;
                   pos=out.pos("\n\n", delim_size=2);
           }
           if(pos<0) {
                   delim_size=0; // calm down, compiler
                   PTHROW(0, 0,
                           &method_name,
                           "output does not contain CGI header; exit code=%d; size=%u; text: \"%s\"", 
                                   exit_code, (uint)out.size(), out.cstr());
         }          }
   
         if(!mime_type)          const String& header=out.mid(0, pos);
                 mime_type=new(pool) String(pool, "application/octet-stream");          const String& body=out.mid(pos+delim_size, out.size());
   
           // body
           self.set(false/*not tainted*/, body.cstr(String::UL_AS_IS), body.size());
   
         static_cast<VFile *>(r.self)->set(data, size, user_file_name, mime_type);          // 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());
           }
   
           // $exit-code
           self.fields().put(
                   *new(pool) String(pool, "exit-code"),
                   new(pool) VInt(pool, exit_code));
           
           // $stderr
           if(err.size()) {
                   self.fields().put(
                           *new(pool) String(pool, "stderr"),
                           new(pool) VString(err));
   
                   SAPI::log(pool, "cgi: %s", err.cstr());
           }
 }  }
   
 // initialize  // constructor
   
   MFile::MFile(Pool& pool) : Methoded(pool) {
           set_name(NEW String(pool, FILE_CLASS_NAME));
   
   
 void initialize_file_class(Pool& pool, VStateless_class& vclass) {  
         // ^save[file-name]          // ^save[file-name]
         vclass.add_native_method("save", Method::CT_DYNAMIC, _save, 1, 1);          add_native_method("save", Method::CT_DYNAMIC, _save, 1, 1);
   
         // ^delete[file-name]          // ^delete[file-name]
         vclass.add_native_method("delete", Method::CT_STATIC, _delete, 1, 1);          add_native_method("delete", Method::CT_STATIC, _delete, 1, 1);
   
         // ^find[file-name]          // ^find[file-name]
         // ^find[file-name]{when-not-found}          // ^find[file-name]{when-not-found}
         vclass.add_native_method("find", Method::CT_STATIC, _find, 1, 2);          add_native_method("find", Method::CT_STATIC, _find, 1, 2);
   
         // ^load[disk-name]          // ^load[disk-name]
         // ^load[disk-name;user-name]          // ^load[disk-name;user-name]
         // ^load[disk-name;user-name;mime-type]          add_native_method("load", Method::CT_DYNAMIC, _load, 1, 2);
         vclass.add_native_method("load", Method::CT_DYNAMIC, _load, 1, 3);  
           // ^stat[disk-name]
           add_native_method("stat", Method::CT_DYNAMIC, _stat, 1, 1);
   
           // ^exec[file-name]
           // ^exec[file-name;env hash]
           // ^exec[file-name;env hash;1cmd;2line;3ar;4g;5s]
           add_native_method("cgi", Method::CT_DYNAMIC, _cgi, 1, 2+5);
   }
   
   // global variable
   
   Methoded *file_class;
   
   // creator
   
   Methoded *MFile_create(Pool& pool) {
           return new(pool) MFile(pool);
 }  }

Removed from v.1.17  
changed lines
  Added in v.1.31.2.2


E-mail: