Diff for /parser3/src/main/pa_request.C between versions 1.3 and 1.61.2.3

version 1.3, 2001/03/10 11:44:42 version 1.61.2.3, 2001/03/21 13:57:29
Line 1 Line 1
 /*  /** @file
 $Id$          Parser: request class main part. @see compile.C and execute.C.
   
           Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
   
           Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)
   
           $Id$
 */  */
   
   #include <string.h>
   
   #include "pa_common.h"
 #include "pa_request.h"  #include "pa_request.h"
 #include "pa_wwrapper.h"  #include "pa_wwrapper.h"
 #include "pa_common.h"  
 #include "pa_vclass.h"  #include "pa_vclass.h"
 #include "classes/_root.h"  #include "_root.h"
 #include "classes/_env.h"  #include "_table.h"
   #include "pa_globals.h"
 #include <stdio.h>  #include "pa_vint.h"
   #include "pa_vmframe.h"
 Request::Request(Pool& apool) : Pooled(apool),  #include "pa_types.h"
   
   Request::Request(Pool& apool,
                                    Info& ainfo,
                                    String::Untaint_lang adefault_lang) : Pooled(apool),
         stack(apool),          stack(apool),
         root_class(apool),          ROOT(apool),
         env_class(apool),          env(apool),
           form(apool),
           request(apool, *this),
           response(apool),
           cookie(apool),
         fclasses(apool),          fclasses(apool),
         fclasses_array(apool),          fdefault_lang(adefault_lang), flang(adefault_lang),
         lang(String::Untaint_lang::HTML_TYPO)          info(ainfo),
           fdefault_content_type(0)
 {  {
         // root class          // root superclass, 
         initialize_root_class(pool(), root_class);  
         // adding root superclass,   
         //   parent of all classes,           //   parent of all classes, 
         //   operators holder          //   operators holder
         String ROOT(pool()); ROOT.APPEND_CONST(ROOT_NAME);          initialize_root_class(pool(), ROOT);
         classes().put(ROOT, &root_class);          classes().put(*root_class_name, &ROOT);
           // table class
           classes().put(*table_class_name, table_class);  
   
         // env class          // env class
         initialize_env_class(pool(), env_class);          classes().put(*env_class_name, &env);
         String ENV(pool()); ENV.APPEND_CONST(ENV_NAME);          // form class
         classes().put(ENV, &env_class);          classes().put(*form_class_name, &form); 
           // request class
           classes().put(*request_class_name, &request);   
           // response class
           classes().put(*response_class_name, &response); 
           // cookie class
           classes().put(*cookie_class_name, &cookie);
   }
   
   static void add_header_attribute(const Hash::Key& aattribute, Hash::Val *ameaning, 
                                                                    void *info) {
           String *attribute_to_exclude=static_cast<String *>(info);
           if(aattribute==*attribute_to_exclude)
                   return;
   
           Value& lmeaning=*static_cast<Value *>(ameaning);
           Pool& pool=lmeaning.pool();
   
           String attribute(pool);
           (*service_funcs.add_header_attribute)(pool,
                   attribute.append(aattribute, String::UL_HEADER, true).cstr(), 
                   attributed_meaning_to_string(lmeaning).cstr());
 }  }
   
 void Request::core() {  void Request::core(const char *sys_auto_path1,
                                      const char *sys_auto_path2,
                                      bool header_only) {
           VStateless_class *main_class=0;
           bool need_rethrow=false;  Exception rethrow_me;
         TRY {          TRY {
                 char *file="Y:\\parser3\\src\\test.p";                  char *auto_filespec=(char *)malloc(MAX_STRING);
                 String RUN(pool()); RUN.APPEND_CONST(RUN_NAME);                  
                 use(file, &RUN);                  // load MAIN class,
                   //      it consists of all the auto.p files we'd manage to find
                   //      plus
                   //      the file user requested us to process
                   //      all located classes become children of one another,
                   //      composing class we name 'MAIN'
   
                   // loading system auto.p 1
                   if(sys_auto_path1) {
                           strncpy(auto_filespec, sys_auto_path1, MAX_STRING-strlen(AUTO_FILE_NAME));
                           strcat(auto_filespec, AUTO_FILE_NAME);
                           main_class=use_file(
                                   auto_filespec, false/*ignore possible read problem*/,
                                   main_class_name, main_class);
                   }
   
                   // loading system auto.p 2
                   if(sys_auto_path2) {
                           strncpy(auto_filespec, sys_auto_path2, MAX_STRING-strlen(AUTO_FILE_NAME));
                           strcat(auto_filespec, AUTO_FILE_NAME);
                           main_class=use_file(
                                   auto_filespec, false/*ignore possible read problem*/,
                                   main_class_name, main_class);
                   }
   
                 char *result=execute_MAIN();                  Value *element;
                 printf("result-----------------\n%sEOF----------------\n", result);                  // $MAIN:limits hash used here,
                   //      until someone with less privileges have overriden them
                   Value *limits=main_class?main_class->get_element(*limits_name):0;
                   // $limits.post_max_size default 10M
                   element=limits?limits->get_element(*post_max_size_name):0;
                   int value=element?(size_t)element->get_double():0;
                   int post_max_size=value?value:10*0x400*400;
   
                   form.fill_fields(*this, post_max_size);
                   cookie.fill_fields(*this);
   
                   // TODO: load site auto.p files, all assigned bases from upper dir
                   /*char *site_auto_file="Y:\\parser3\\src\\auto.p";
                   main_class=use_file(
                           site_auto_file, false/*ignore possible read problem* /,
                           main_class_name, main_class);*/
   
                   // $MAIN:defaults
                   Value *defaults=main_class?main_class->get_element(*defaults_name):0;
                   fdefault_content_type=defaults?defaults->get_element(*content_type_name):0;
   
                   // there must be some auto.p
                   if(/*\*/0&&!main_class)
                           THROW(0,0,
                                   0,
                                   "no 'auto.p' found (nither system nor any site's)");
   
                   // compiling requested file
                   main_class=use_file(info.path_translated, true/*don't ignore read problem*/,
                           main_class_name, main_class);
   
                   // execute @main[]
                   const String *body_string=execute_method(*main_class, *main_method_name);
                   if(!body_string)
                           THROW(0,0,
                           0, 
                           "'"MAIN_METHOD_NAME"' method not found");
   
                   // extract response body
                   Value *body_value=static_cast<Value *>(
                           response.fields().get(*body_name));
                   if(body_value) // there is some $request.body
                           body_string=&body_value->as_string();// TODO: IMAGE&FILE
   
                   // OK. write out the result
                   output_result(*body_string, header_only);
         }           } 
         CATCH(e) {          CATCH(e) {
                 printf("\nERROR: ");                  TRY {
                 const String *problem_source=e.problem_source();                          // we're returning not result, but error explanation
                 if(problem_source) {  
                         const Origin& origin=problem_source->origin();                          // reset language to default
                         if(origin.file)                          flang=fdefault_lang;
                                 printf("%s(%d): ",                          
                                 origin.file, 1+origin.line);                          // reset response
                         printf("'%s' ",                           response.fields().clear();
                                 problem_source->cstr());  
                           // this is what we'd return in $response:body
                           const String *body_string=0;
   
                           if(main_class) { // we've managed to end up with some main_class
                                   // maybe we'd be lucky enough as to report an error
                                   // in a gracefull way...
                                   if(Value *value=main_class->get_element(*exception_method_name))
                                           if(Junction *junction=value->get_junction())
                                                   if(const Method *method=junction->method) {
                                                           // preparing to pass parameters to 
                                                           //      @exception[origin;source;comment;type;code]
                                                           VMethodFrame frame(pool(), *junction);
                                                           frame.set_self(*main_class);
   
                                                           const String *problem_source=e.problem_source();
                                                           // origin
                                                           String origin_name(pool(), "origin");
                                                           Value *origin_value=0;
   #ifndef NO_STRING_ORIGIN
                                                           if(problem_source) {
                                                                   const Origin& origin=problem_source->origin();
                                                                   if(origin.file) {
                                                                           char *buf=(char *)malloc(MAX_STRING);
                                                                           snprintf(buf, MAX_STRING, "%s(%d):", 
                                                                                   origin.file, 1+origin.line);
                                                                           String *origin_file_line=NEW String(pool(),
                                                                                   buf, true);
                                                                           origin_value=NEW VString(*origin_file_line);
                                                                   }
                                                           }
   #endif
                                                           frame.store_param(origin_name, 
                                                                   origin_value?origin_value:NEW VUnknown(pool()));
   
                                                           // source
                                                           String source_name(pool(), "source");
                                                           Value *source_value=0;
                                                           if(problem_source) {
                                                                   String& problem_source_copy=*NEW String(pool());
                                                                   problem_source_copy.append(*problem_source, 
                                                                           flang, true);
                                                                   source_value=NEW VString(problem_source_copy);
                                                           }
                                                           frame.store_param(source_name, 
                                                                   source_value?source_value:NEW VUnknown(pool()));
   
                                                           // comment
                                                           String comment_name(pool(), "comment");
                                                           String *comment_value=NEW String(pool(),
                                                                   e.comment(), true);
                                                           frame.store_param(comment_name, 
                                                                   NEW VString(*comment_value));
   
                                                           // type
                                                           String type_name(pool(), "type");
                                                           Value *type_value;
                                                           if(e.type()) {
                                                                   String& type_copy=*NEW String(pool());
                                                                   type_value=NEW VString(type_copy.append(*e.type(), 
                                                                           flang, true));
                                                           } else
                                                                   type_value=NEW VUnknown(pool());
                                                           frame.store_param(type_name, type_value);
   
                                                           // code
                                                           String code_name(pool(), "code");
                                                           Value *code_value;
                                                           if(e.code()) {
                                                                   String& code_copy=*NEW String(pool());
                                                                   code_value=NEW VString(code_copy.append(*e.code(), 
                                                                           flang, true));
                                                           } else
                                                                   code_value=NEW VUnknown(pool());
                                                           frame.store_param(code_name, code_value);
   
                                                           // future $response:body=
                                                           //   execute ^exception[origin;source;comment;type;code]
                                                           body_string=execute_method(frame, *method);
                                                   }
                           }
                           
                           if(!body_string) {  // couldn't report an error beautifully?
                                   // doing that ugly
   
                                   // make up result: $origin $source $comment $type $code
                                   char *buf=(char *)malloc(MAX_STRING);
                                   size_t printed=0;
                                   const String *problem_source=e.problem_source();
                                   if(problem_source) {
   #ifndef NO_STRING_ORIGIN
                                           const Origin& origin=problem_source->origin();
                                           if(origin.file)
                                                   printed+=snprintf(buf+printed, MAX_STRING-printed, "%s(%d): ", 
                                                   origin.file, 1+origin.line);
   #endif
                                           printed+=snprintf(buf+printed, MAX_STRING-printed, "'%s' ", 
                                                   problem_source->cstr());
                                   }
                                   printed+=snprintf(buf+printed, MAX_STRING-printed, "%s", 
                                           e.comment());
                                   const String *type=e.type();
                                   if(type) {
                                           printed+=snprintf(buf+printed, MAX_STRING-printed, "  type: %s", 
                                                   type->cstr());
                                           const String *code=e.code();
                                           if(code)
                                                   printed+=snprintf(buf+printed, MAX_STRING-printed, ", code: %s", 
                                                   code->cstr());
                                   }
   
                                   // future $response:content-type
                                   response.fields().put(*content_type_name, 
                                           NEW VString(*NEW String(pool(), "text/plain")));
                                   // future $response:body
                                   body_string=NEW String(pool(), buf);
                           }
   
                           // ERROR. write it out
                           output_result(*body_string, header_only);
                 }                  }
                 printf("%s", e.comment());                  CATCH(e) {
                 const String *type=e.type();                          // exception in request exception handler
                 if(type) {                          // remember to rethrow it
                         printf("  type: %s", type->cstr());                          rethrow_me=e;  need_rethrow=true; 
                         const String *code=e.code();  
                         if(code)  
                                 printf(", code: %s", code->cstr());  
                 }                  }
                 printf("\n");                  END_CATCH
         }          }
         END_CATCH          END_CATCH // do not use pool() after this point - no exception handler set
                     // any throw() would try to use zero exception() pointer 
   
           if(need_rethrow) // there were an exception set for us to rethrow?
                   THROW(rethrow_me.type(), rethrow_me.code(),
                           rethrow_me.problem_source(),
                           rethrow_me.comment());
   
 }  }
   
 void Request::use(char *file, String *name) {  /// @todo find|solve cyclic dependences
         // TODO: обнаружить|решить cyclic dependences  VStateless_class *Request::use_file(
         char *source=file_read(pool(), file);                                                                          const char *file, bool fail_on_read_problem,
                                                                           const String *name, 
                                                                           VStateless_class *base_class) {
           char *source=file_read_text(pool(), file, fail_on_read_problem);
         if(!source)          if(!source)
                 THROW(0,0,                  return base_class;
                         0,  
                         "use: can not read '%s' file", file);          return use_buf(source, file, 0/*new class*/, name, base_class);
   }
         COMPILE(source, name, file);  
         // TODO: запустить @STATIC[], если есть  VStateless_class *Request::use_buf(
                                                                      const char *source, const char *file,
 //      if(alias)                                                                     VStateless_class *aclass, const String *name, 
                 //classes().put(*alias, &vclass);                                                                     VStateless_class *base_class) {
 }          // compile loaded class
           VStateless_class& cclass=COMPILE(source, aclass, name, base_class, file);
 char *Request::execute_MAIN() {  
         // locate class with @main & it's code          // locate and execute possible @auto[] static method
         String name_main(pool());          execute_method(cclass, *auto_method_name, false /*no result needed*/);
         name_main.APPEND_CONST(MAIN_METHOD_NAME);          return &cclass;
   }
         // looking for latest known @main  
         for(int i=classes_array().size(); --i>=0;) {  /**
                 VClass *vclass=static_cast<VClass *>(classes_array().get(i));          - fail_if_junction(true, junction = fail
                 Value *main=vclass->get_element(name_main);          - fail_if_junction(false, not junction = fail
                 if(main) { // found some 'main' element  */
                         Junction *junction=main->get_junction();  void Request::fail_if_junction_(bool is, Value& value, 
                         if(junction) {// it even has junction!                                                                  const String& method_name, const char *msg) {
                                 const Method *method=junction->method;  
                                 if(method) { // and junction is method-junction! call it          if((value.get_junction()!=0) ^ !is)
                                         // initialize contexts                  THROW(0, 0,
                                         root=rcontext=self=vclass;                          &method_name,
                                         wcontext=NEW WWrapper(pool(), vclass, false /* not constructing */);                          msg);
                                           }
                                         // execute!       
                                         execute(*method->parser_code);  char *Request::relative(const char *path, const char *file) {
                                               char *result=(char *)malloc(strlen(path)+strlen(file)+1);
                                         // return chars          strcpy(result, path);
                                         return wcontext->get_string()->cstr();      rsplit(result, PATH_DELIMITER_CHAR);
                                 }      strcat(result, PATH_DELIMITER_STRING);
                         }      strcat(result, file);
                 }      return result;
         }  }
   
   char *Request::absolute(const char *name) {
           if(name[0]=='/') {
                   char *result=(char *)malloc(strlen(info.document_root)+strlen(name)+1);
                   strcpy(result, info.document_root);
                   strcat(result, name);
                   return result;
           } else 
                   return relative(info.path_translated, name);
   }
   
   void Request::output_result(const String& body_string, bool header_only) {
           // header: cookies
           cookie.output_result();
                   
         THROW(0,0,          // set default content-type
                 0,           if(fdefault_content_type)
                 "'"MAIN_METHOD_NAME"' method not found");                  response.fields().put_dont_replace(*content_type_name, fdefault_content_type);
         return 0;  
           // prepare header: $response:fields without :body
           response.fields().foreach(add_header_attribute, /*excluding*/ body_name);
   
           // prepare...
           const char *body=body_string.cstr();
           size_t content_length=strlen(body);
   
           // prepare header: content-length
           char content_length_cstr[MAX_NUMBER];
           snprintf(content_length_cstr, MAX_NUMBER, "%d", content_length);
           (*service_funcs.add_header_attribute)(pool(), "content-length", content_length_cstr);
   
           // send header
           (*service_funcs.send_header)(pool());
   
           // send body
           if(!header_only)
                   (*service_funcs.send_body)(pool(), body, content_length);
 }  }

Removed from v.1.3  
changed lines
  Added in v.1.61.2.3


E-mail: