Diff for /parser3/src/main/pa_request.C between versions 1.274 and 1.298

version 1.274, 2005/07/08 14:06:11 version 1.298, 2008/07/15 12:54:37
Line 1 Line 1
 /** @file  /** @file
         Parser: request class main part. @see compile.C and execute.C.          Parser: request class main part. @see compile.C and execute.C.
   
         Copyright (c) 2001-2004 ArtLebedev Group (http://www.artlebedev.com)          Copyright (c) 2001-2005 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)
 */  */
   
Line 53  const char* ORIGINS_CONTENT_TYPE="text/p Line 53  const char* ORIGINS_CONTENT_TYPE="text/p
 #define EXCEPTION_TYPE_PART_NAME "type"  #define EXCEPTION_TYPE_PART_NAME "type"
 #define EXCEPTION_SOURCE_PART_NAME "source"  #define EXCEPTION_SOURCE_PART_NAME "source"
 #define EXCEPTION_COMMENT_PART_NAME "comment"  #define EXCEPTION_COMMENT_PART_NAME "comment"
 #define RESPONSE_BODY_FILE_NAME "file"  
   
 // globals  // globals
   
 const String main_method_name(MAIN_METHOD_NAME);  const String main_method_name(MAIN_METHOD_NAME);
 const String auto_method_name(AUTO_METHOD_NAME);  const String auto_method_name(AUTO_METHOD_NAME);
   const String content_transfer_encoding_name(CONTENT_TRANSFER_ENCODING_NAME);
 const String content_disposition_name(CONTENT_DISPOSITION_NAME);  const String content_disposition_name(CONTENT_DISPOSITION_NAME);
 const String content_disposition_value(CONTENT_DISPOSITION_VALUE);  const String content_disposition_inline(CONTENT_DISPOSITION_INLINE);
   const String content_disposition_attachment(CONTENT_DISPOSITION_ATTACHMENT);
 const String content_disposition_filename_name(CONTENT_DISPOSITION_FILENAME_NAME);  const String content_disposition_filename_name(CONTENT_DISPOSITION_FILENAME_NAME);
 const String body_name(BODY_NAME);  const String body_name(BODY_NAME);
 const String exception_type_part_name(EXCEPTION_TYPE_PART_NAME);  const String exception_type_part_name(EXCEPTION_TYPE_PART_NAME);
 const String exception_source_part_name(EXCEPTION_SOURCE_PART_NAME);  const String exception_source_part_name(EXCEPTION_SOURCE_PART_NAME);
 const String exception_comment_part_name(EXCEPTION_COMMENT_PART_NAME);  const String exception_comment_part_name(EXCEPTION_COMMENT_PART_NAME);
 const String exception_handled_part_name(EXCEPTION_HANDLED_PART_NAME);  const String exception_handled_part_name(EXCEPTION_HANDLED_PART_NAME);
 const String response_body_file_name(RESPONSE_BODY_FILE_NAME);  
   
 // defines for statics  // defines for statics
   
Line 78  const String response_body_file_name(RES Line 78  const String response_body_file_name(RES
 #define POST_PROCESS_METHOD_NAME "postprocess"  #define POST_PROCESS_METHOD_NAME "postprocess"
 #define DOWNLOAD_NAME "download"  #define DOWNLOAD_NAME "download"
 #define CLASS_PATH_NAME "CLASS_PATH"  #define CLASS_PATH_NAME "CLASS_PATH"
   #define RESPONSE_BODY_FILE_NAME "file"
   
 // statics  // statics
   
Line 89  static const String conf_method_name(CON Line 90  static const String conf_method_name(CON
 static const String post_process_method_name(POST_PROCESS_METHOD_NAME);  static const String post_process_method_name(POST_PROCESS_METHOD_NAME);
 static const String download_name(DOWNLOAD_NAME);  static const String download_name(DOWNLOAD_NAME);
 static const String class_path_name(CLASS_PATH_NAME);  static const String class_path_name(CLASS_PATH_NAME);
   static const String response_body_file_name(RESPONSE_BODY_FILE_NAME);
   
 // defines  // defines
   
Line 107  Request::Request(SAPI_Info& asapi_info, Line 109  Request::Request(SAPI_Info& asapi_info,
         wcontext(0),          wcontext(0),
         flang(adefault_lang),          flang(adefault_lang),
         fconnection(0),          fconnection(0),
         finterrupted(false),          finterrupted(false),fskip(SKIP_NOTHING),
   
         // public          // public
 #ifdef RESOURCES_DEBUG  #ifdef RESOURCES_DEBUG
Line 124  Request::Request(SAPI_Info& asapi_info, Line 126  Request::Request(SAPI_Info& asapi_info,
         form(*new VForm(charsets, arequest_info)),          form(*new VForm(charsets, arequest_info)),
         mail(*new VMail),          mail(*new VMail),
         response(*new VResponse(arequest_info, charsets)),          response(*new VResponse(arequest_info, charsets)),
         cookie(*new VCookie),          cookie(*new VCookie(charsets, arequest_info)),
           console(*new VConsole),
   
         // private          // private
         configure_admin_done(false),          configure_admin_done(false),
Line 157  Request::Request(SAPI_Info& asapi_info, Line 160  Request::Request(SAPI_Info& asapi_info,
         if(status_allowed)          if(status_allowed)
                 classes().put(String::Body(STATUS_CLASS_NAME), new VStatus());                  classes().put(String::Body(STATUS_CLASS_NAME), new VStatus());
         // request class          // request class
         classes().put(String::Body(REQUEST_CLASS_NAME), new VRequest(arequest_info, charsets));           classes().put(String::Body(REQUEST_CLASS_NAME), new VRequest(arequest_info, charsets, form));   
         // cookie class          // cookie class
         classes().put(String::Body(COOKIE_CLASS_NAME), &cookie);          classes().put(String::Body(COOKIE_CLASS_NAME), &cookie);
         // console class          // console class
         classes().put(String::Body(CONSOLE_CLASS_NAME), new VConsole());          classes().put(String::Body(CONSOLE_CLASS_NAME), &console);
   
         /// methoded          /// methoded
         // response class          // response class
         classes().put(response.get_class()->name(), &response);          classes().put(response.get_class()->name(), &response);
Line 204  static void load_charset(HashStringValue Line 206  static void load_charset(HashStringValue
 }  }
 void Request::configure_admin(VStateless_class& conf_class) {  void Request::configure_admin(VStateless_class& conf_class) {
         if(configure_admin_done)          if(configure_admin_done)
                 throw Exception("parser.runtime",                  throw Exception(PARSER_RUNTIME,
                 0,                  0,
                 "parser already configured");                  "parser already configured");
         configure_admin_done=true;          configure_admin_done=true;
Line 220  void Request::configure_admin(VStateless Line 222  void Request::configure_admin(VStateless
         if(Value* vcharsets=conf_class.get_element(charsets_name, conf_class, false)) {          if(Value* vcharsets=conf_class.get_element(charsets_name, conf_class, false)) {
                 if(!vcharsets->is_string())                  if(!vcharsets->is_string())
                         if(HashStringValue* charsets=vcharsets->get_hash())                          if(HashStringValue* charsets=vcharsets->get_hash())
                                 charsets->for_each(load_charset, &this->charsets);                                  charsets->for_each<Request_charsets*>(load_charset, &this->charsets);
                         else                          else
                                 throw Exception("parser.runtime",                                  throw Exception(PARSER_RUNTIME,
                                         0,                                          0,
                                         "$" MAIN_CLASS_NAME ":" CHARSETS_NAME " must be hash");                                          "$" MAIN_CLASS_NAME ":" CHARSETS_NAME " must be hash");
         }          }
Line 304  struct timeval mt[10]; Line 306  struct timeval mt[10];
 gettimeofday(&mt[0],NULL);  gettimeofday(&mt[0],NULL);
 #endif  #endif
         try {          try {
                 // filling cookies  
                 cookie.fill_fields(request_info);  
   
                 // filling mail received                  // filling mail received
                 mail.fill_received(*this);                  mail.fill_received(*this);
   
Line 373  gettimeofday(&mt[1],NULL); Line 372  gettimeofday(&mt[1],NULL);
                 // execute @main[]                  // execute @main[]
                 const String* body_string=execute_virtual_method(main_class, main_method_name);                  const String* body_string=execute_virtual_method(main_class, main_method_name);
                 if(!body_string)                  if(!body_string)
                         throw Exception("parser.runtime",                          throw Exception(PARSER_RUNTIME,
                                 0,                                  0,
                                 "'"MAIN_METHOD_NAME"' method not found");                                  "'"MAIN_METHOD_NAME"' method not found");
   
Line 389  gettimeofday(&mt[2],NULL); Line 388  gettimeofday(&mt[2],NULL);
                         body_value=response.fields().get(body_name); // $response:body                          body_value=response.fields().get(body_name); // $response:body
                 if(!body_value)                  if(!body_value)
                         body_value=new VString(*body_string); // just result of ^main[]                          body_value=new VString(*body_string); // just result of ^main[]
                   // ensure that body_value has no just L_TAINTED parts left
                   if(body_value->is_string())
                   {
                           String& untainted=*new String();
                           untainted.append(*body_value->get_string(), flang);
                           body_value=new VString(untainted);
                   }
   
                 // @postprocess                  // @postprocess
                 if(Value* value=main_class.get_element(post_process_method_name, main_class, false))                  if(Value* value=main_class.get_element(post_process_method_name, main_class, false))
Line 456  t[9]-t[3] Line 462  t[9]-t[3]
                                 false)) {                                  false)) {
                         if(Junction* junction=value->get_junction()) {                          if(Junction* junction=value->get_junction()) {
                                 if(const Method *method=junction->method) {                                  if(const Method *method=junction->method) {
 // preparing to pass parameters to                                           // preparing to pass parameters to 
 //      @unhandled_exception[exception;stack]                                          //      @unhandled_exception[exception;stack]
 VMethodFrame frame(/*method->name, */ *junction, 0/*no caller*/);                                          VMethodFrame frame(/*method->name, */ *junction, 0/*no caller*/);
 frame.set_self(main_class);                                          frame.set_self(main_class);
   
 // $exception                                          // $exception
 frame.store_param(details.vhash);                                          frame.store_param(details.vhash);
 // $stack[^table::set{name      origin}]                                          // $stack[^table::create{name   file    lineno  colno}]
 Table::columns_type stack_trace_columns(new ArrayString);                                          Table::columns_type stack_trace_columns(new ArrayString);
 *stack_trace_columns+=new String("name");                                          *stack_trace_columns+=new String("name");
 *stack_trace_columns+=new String("file");                                          *stack_trace_columns+=new String("file");
 *stack_trace_columns+=new String("lineno");                                          *stack_trace_columns+=new String("lineno");
 *stack_trace_columns+=new String("colno");                                          *stack_trace_columns+=new String("colno");
 Table& stack_trace=*new Table(stack_trace_columns);                                          Table& stack_trace=*new Table(stack_trace_columns);
 if(!exception_trace.is_empty()/*signed!*/)                                           if(!exception_trace.is_empty()/*signed!*/) 
 for(size_t i=exception_trace.bottom_index(); i<exception_trace.top_index(); i++) {                                                  for(size_t i=exception_trace.bottom_index(); i<exception_trace.top_index(); i++) {
         Trace trace=exception_trace.get(i);                                                          Trace trace=exception_trace.get(i);
         Table::element_type row(new ArrayString);                                                          Table::element_type row(new ArrayString);
   
         *row+=trace.name(); // name column                                                          *row+=trace.name(); // name column
         Operation::Origin origin=trace.origin();                                                          Operation::Origin origin=trace.origin();
         if(origin.file_no) {                                                          if(origin.file_no) {
                 *row+=new String(file_list[origin.file_no], String::L_TAINTED); // 'file' column                                                                  *row+=new String(file_list[origin.file_no], String::L_TAINTED); // 'file' column
                 *row+=new String(String::Body::Format(1+origin.line), String::L_CLEAN); // 'lineno' column                                                                  *row+=new String(String::Body::Format(1+origin.line), String::L_CLEAN); // 'lineno' column
                 *row+=new String(String::Body::Format(1+origin.col), String::L_CLEAN); // 'colno' column                                                                  *row+=new String(String::Body::Format(1+origin.col), String::L_CLEAN); // 'colno' column
         }                                                          }
         stack_trace+=row;                                                          stack_trace+=row;
 }                                                  }
 frame.store_param(*new VTable(&stack_trace));  
                                           frame.store_param(*new VTable(&stack_trace));
 // future $response:body=  
 //   execute ^unhandled_exception[exception;stack]                                          // future $response:body=
 body_string=&execute_method(frame, *method).as_string();                                          //   execute ^unhandled_exception[exception;stack]
                                           exception_trace.clear(); // forget all about previous life, in case there would be error inside of this method, error handled  would not be mislead by old stack contents (see extract_origin)
                                           body_string=&execute_method(frame, *method).as_string();
                                 }                                  }
                         }                          }
                 }                  }
Line 514  body_string=&execute_method(frame, *meth Line 522  body_string=&execute_method(frame, *meth
   
                 // ERROR. write it out                  // ERROR. write it out
                 output_result(body_file, header_only, false);                  output_result(body_file, header_only, false);
   
                 } catch(const Exception& e) { // exception in unhandled exception                  } catch(const Exception& e) { // exception in unhandled exception
                         Request::Exception_details details=get_details(e);                          Request::Exception_details details=get_details(e);
                         const char* exception_cstr=get_exception_cstr(e, details);                          const char* exception_cstr=get_exception_cstr(e, details);
Line 552  void Request::use_file(VStateless_class& Line 561  void Request::use_file(VStateless_class&
                 file_spec=0;                  file_spec=0;
                 if(Value* element=main_class.get_element(class_path_name, main_class, false)) {                  if(Value* element=main_class.get_element(class_path_name, main_class, false)) {
                         if(element->is_string()) {                          if(element->is_string()) {
                                 file_spec=file_readable(absolute(element->as_string()), file_name); // found at class_path?                                  file_spec=file_exist(absolute(element->as_string()), file_name); // found at class_path?
                         } else if(Table *table=element->get_table()) {                          } else if(Table *table=element->get_table()) {
                                 int size=table->count();                                  int size=table->count();
                                 for(int i=size; i--; ) {                                  for(int i=size; i--; ) {
                                         const String& path=*(*table->get(i))[0];                                          const String& path=*(*table->get(i))[0];
                                         if((file_spec=file_readable(absolute(path), file_name)))                                          if((file_spec=file_exist(absolute(path), file_name)))
                                                 break; // found along class_path                                                  break; // found along class_path
                                 }                                  }
                         } else                          } else
                                 throw Exception("parser.runtime",                                  throw Exception(PARSER_RUNTIME,
                                         0,                                          0,
                                         "$" CLASS_PATH_NAME " must be string or table");                                          "$" CLASS_PATH_NAME " must be string or table");
                         if(!file_spec)                          if(!file_spec)
                                 throw Exception("parser.runtime",                                  throw Exception(PARSER_RUNTIME,
                                         &file_name,                                          &file_name,
                                         "not found along " MAIN_CLASS_NAME ":" CLASS_PATH_NAME);                                          "not found along " MAIN_CLASS_NAME ":" CLASS_PATH_NAME);
                 }                  }
                 if(!file_spec)                  if(!file_spec)
                         throw Exception("parser.runtime",                          throw Exception(PARSER_RUNTIME,
                                 &file_name,                                  &file_name,
                                 "usage failed - no $" MAIN_CLASS_NAME  ":" CLASS_PATH_NAME " were specified");                                  "usage failed - no $" MAIN_CLASS_NAME  ":" CLASS_PATH_NAME " were specified");
         }          }
Line 593  void Request::use_buf(VStateless_class& Line 602  void Request::use_buf(VStateless_class&
         // temporary zero @auto so to maybe-replace it in compiled code          // temporary zero @auto so to maybe-replace it in compiled code
         Temp_method temp_method_auto(aclass, auto_method_name, 0);          Temp_method temp_method_auto(aclass, auto_method_name, 0);
   
         // compile loaded class          // compile loaded classes
         VStateless_class& cclass=compile(&aclass, source, main_alias, file_no, line_no_offset);          ArrayClass& cclasses=compile(&aclass, source, main_alias, file_no, line_no_offset);
   
         // locate and execute possible @conf[] static  
         VString* vfilespec=          VString* vfilespec=
                 new VString(*new String(file_list[file_no], String::L_TAINTED));                  new VString(*new String(file_list[file_no], String::L_TAINTED));
         Execute_nonvirtual_method_result executed=execute_nonvirtual_method(cclass,   
                 conf_method_name, vfilespec,          for(size_t i=0; i<cclasses.count(); i++){
                 false/*no string result needed*/);                  VStateless_class& cclass=*cclasses.get(i);
         if(executed.method)  
                 configure_admin(cclass/*, executed.method->name*/);                  // locate and execute possible @conf[] static
                   Execute_nonvirtual_method_result executed=execute_nonvirtual_method(cclass, 
         // locate and execute possible @auto[] static                          conf_method_name, vfilespec,
         execute_nonvirtual_method(cclass,                           false/*no string result needed*/);
                 auto_method_name, vfilespec,                  if(executed.method)
                 false/*no result needed*/);                          configure_admin(cclass/*, executed.method->name*/);
   
                   // locate and execute possible @auto[] static
                   execute_nonvirtual_method(cclass, 
                           auto_method_name, vfilespec,
                           false/*no result needed*/);
           }
 }  }
   
 const String& Request::relative(const char* apath, const String& relative_name) {  const String& Request::relative(const char* apath, const String& relative_name) {
Line 648  public: Line 662  public:
 };  };
 #endif  #endif
 static void add_header_attribute(  static void add_header_attribute(
                                  HashStringValue::key_type aattribute,                                    HashStringValue::key_type name, 
                                  HashStringValue::value_type ameaning,                                    HashStringValue::value_type value, 
                                  Add_header_attribute_info* info) {                                   Add_header_attribute_info* info) {
         if(aattribute==BODY_NAME          if(name==BODY_NAME
                 || aattribute==DOWNLOAD_NAME                  || name==DOWNLOAD_NAME
                 || aattribute==CHARSET_NAME)                  || name==CHARSET_NAME)
                 return;                  return;
           
           const char* aname=String(name, String::L_URI).cstr(String::L_UNSPECIFIED, 0, &info->r.charsets);
   
         const char* a=aattribute.cstr();  
         SAPI::add_header_attribute(info->r.sapi_info,          SAPI::add_header_attribute(info->r.sapi_info,
                 a,                   aname, 
                 attributed_meaning_to_string(*ameaning, String::L_HTTP_HEADER, false).                  attributed_meaning_to_string(*value, String::L_URI, false).cstr(String::L_UNSPECIFIED, 0, &info->r.charsets));
                         cstr(String::L_UNSPECIFIED));  
   
         if(strcasecmp(a, "last-modified")==0)          if(strcasecmp(aname, "last-modified")==0)
                 info->add_last_modified = false;                  info->add_last_modified = false;
 }  }
   
Line 830  void Request::output_result(VFile* body_ Line 844  void Request::output_result(VFile* body_
                 if(sfile_name!=NONAME_DAT) {                  if(sfile_name!=NONAME_DAT) {
                         VHash& hash=*new VHash();                          VHash& hash=*new VHash();
                         HashStringValue &h=hash.hash();                          HashStringValue &h=hash.hash();
                         if(as_attachment)                          h.put(value_name, new VString( as_attachment ? content_disposition_attachment : content_disposition_inline ));
                                 h.put(value_name, new VString(content_disposition_value));  
                         h.put(content_disposition_filename_name, vfile_name);                          h.put(content_disposition_filename_name, vfile_name);
                         response.fields().put(content_disposition_name, &hash);                          response.fields().put(content_disposition_name, &hash);
   
Line 852  void Request::output_result(VFile* body_ Line 866  void Request::output_result(VFile* body_
   
         // prepare header: $response:fields without :body          // prepare header: $response:fields without :body
         Add_header_attribute_info info(*this);          Add_header_attribute_info info(*this);
         response.fields().for_each(add_header_attribute, &info);          response.fields().for_each<Add_header_attribute_info*>(add_header_attribute, &info);
   
         if(body_file_content_type)          if(body_file_content_type)
                 if(HashStringValue *hash=body_file_content_type->get_hash())                  if(HashStringValue *hash=body_file_content_type->get_hash())
Line 871  void Request::output_result(VFile* body_ Line 885  void Request::output_result(VFile* body_
                         if(Value* vdatep=v->as(VDATE_TYPE, false))                          if(Value* vdatep=v->as(VDATE_TYPE, false))
                                 vdate=static_cast<VDate*>(vdatep);                                  vdate=static_cast<VDate*>(vdatep);
                         else                           else 
                                 throw Exception("parser.runtime", 0, "mdate must be a date");                                  throw Exception(PARSER_RUNTIME, 0, "mdate must be a date");
                 }                  }
                 if(!vdate)                  if(!vdate)
                         vdate=new VDate(mtime);                          vdate=new VDate(mtime);
Line 896  const String& Request::mime_type_of(cons Line 910  const String& Request::mime_type_of(cons
                                         if(const String* result=mime_types->item(1))                                          if(const String* result=mime_types->item(1))
                                                 return *result;                                                  return *result;
                                 else                                  else
                                         throw Exception("parser.runtime",                                          throw Exception(PARSER_RUNTIME,
                                                 0,                                                  0,
                                                 MIME_TYPES_NAME  " table column elements must not be empty");                                                  MIME_TYPES_NAME  " table column elements must not be empty");
                 }                  }
Line 905  const String& Request::mime_type_of(cons Line 919  const String& Request::mime_type_of(cons
 }  }
   
 #ifdef XML  #ifdef XML
 GdomeDOMString_auto_ptr Request::transcode(const String& s) {  xmlChar* Request::transcode(const String& s) {
         return charsets.source().transcode(s);          return charsets.source().transcode(s);
 }  }
   
 GdomeDOMString_auto_ptr Request::transcode(const String::Body s) {  xmlChar* Request::transcode(const String::Body s) {
         return charsets.source().transcode(s);          return charsets.source().transcode(s);
 }  }
   
 const String& Request::transcode(GdomeDOMString* s) {  const String& Request::transcode(const xmlChar* s) {
         return charsets.source().transcode(s);  
 }  
   
 const String& Request::transcode(xmlChar* s) {  
         return charsets.source().transcode(s);          return charsets.source().transcode(s);
 }  }
 #endif  #endif
Line 928  const Request::Trace Request::Exception_ Line 938  const Request::Trace Request::Exception_
         if(!is_empty()) {          if(!is_empty()) {
                 result=bottom_value();                  result=bottom_value();
                 if(!problem_source) { // we don't know who trigged the bug?                  if(!problem_source) { // we don't know who trigged the bug?
                         problem_source=result.name(); // consider the stack-top-guy did that                          problem_source=result.name(); // consider the stack-top-guy (we usually know source of next-from-throw-point exception) did that
                         fbottom++;                          fbottom++;
                 } else if(result.name()==problem_source) // it is that same guy?                  } else if(result.name()==problem_source) // it is that same guy?
                         fbottom++; // throw away that trace                          fbottom++; // throw away that trace
                 // else stack top contains not us,                   else {
                 //      leaving result intact                          // stack top contains not us, 
                 //      it would help ^throw                          //      leaving result intact
                           //      it would help ^throw
                   }
         }          }
   
         return result;          return result;

Removed from v.1.274  
changed lines
  Added in v.1.298


E-mail: