Diff for /parser3/src/main/pa_request.C between versions 1.47 and 1.93

version 1.47, 2001/03/18 17:18:36 version 1.93, 2001/04/03 07:54:25
Line 1 Line 1
 /*  /** @file
         Parser          Parser: request class main part. @see compile.C and execute.C.
   
         Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)          Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
   
         Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)          Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)
   
         $Id$          $Id$
 */  */
   
 #include <string.h>  #include "pa_config_includes.h"
   
   #include "pa_sapi.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 "_root.h"  #include "_root.h"
 #include "_env.h"  
 #include "_table.h"  #include "_table.h"
   #include "_file.h"
 #include "pa_globals.h"  #include "pa_globals.h"
 #include "pa_vint.h"  #include "pa_vint.h"
 #include "pa_vmframe.h"  #include "pa_vmframe.h"
 #include "pa_types.h"  #include "pa_types.h"
   #include "pa_vtable.h"
   #include "_random.h"
   #include "pa_vfile.h"
   
   /// $limits.post_max_size default 10M
   const size_t MAX_POST_SIZE_DEFAULT=10*0x400*400;
   
   /// content type of exception response, when no @MAIN:exception handler defined
   const char *UNHANDLED_EXCEPTION_CONTENT_TYPE="text/plain";
   
   /// content type of response when no $MAIN:defaults.content-type defined
   const char *DEFAULT_CONTENT_TYPE="text/html";
   
   //
 Request::Request(Pool& apool,  Request::Request(Pool& apool,
                                  Info& ainfo,                                   Info& ainfo,
                                  String::Untaint_lang adefault_lang) : Pooled(apool),                                   String::Untaint_lang adefault_lang) : Pooled(apool),
Line 29  Request::Request(Pool& apool, Line 45  Request::Request(Pool& apool,
         form(apool),          form(apool),
         request(apool, *this),          request(apool, *this),
         response(apool),          response(apool),
           cookie(apool),
         fclasses(apool),          fclasses(apool),
         fdefault_lang(adefault_lang), flang(adefault_lang),          fdefault_lang(adefault_lang), flang(adefault_lang),
         info(ainfo),          info(ainfo),
         fdefault_content_type(0)          used_files(apool),
           default_content_type(0),
           mime_types(0)
 {  {
         // root superclass,           // root superclass, 
         //   parent of all classes,           //   parent of all classes, 
Line 41  Request::Request(Pool& apool, Line 60  Request::Request(Pool& apool,
         classes().put(*root_class_name, &ROOT);          classes().put(*root_class_name, &ROOT);
         // table class          // table class
         classes().put(*table_class_name, table_class);            classes().put(*table_class_name, table_class);  
 //      table_class->set_name(*table_class_name);          // file class
           classes().put(*file_class_name, file_class);    
           // random class
           classes().put(*random_class_name, random_class);        
         // env class          // env class
         classes().put(*env_class_name, &env);          classes().put(*env_class_name, &env);
         // form class          // form class
Line 51  Request::Request(Pool& apool, Line 72  Request::Request(Pool& apool,
         classes().put(*request_class_name, &request);             classes().put(*request_class_name, &request);   
         // response class          // response class
         classes().put(*response_class_name, &response);           classes().put(*response_class_name, &response); 
           // cookie class
           classes().put(*cookie_class_name, &cookie);
 }  }
   
 static void append_attribute_subattribute(const Hash::Key& akey, Hash::Value *avalue,   static void add_header_attribute(const Hash::Key& aattribute, Hash::Val *ameaning, 
                                                                                   void *info) {                                                                   void *info) {
         if(akey==VALUE_NAME)          String *attribute_to_exclude=static_cast<String *>(info);
           if(aattribute==*attribute_to_exclude)
                 return;                  return;
   
         // ...; charset=windows1251          Value& lmeaning=*static_cast<Value *>(ameaning);
         String *string=static_cast<String *>(info);          Pool& pool=lmeaning.pool();
         string->APPEND_CONST("; ");  
           
         string->append(akey, String::Untaint_lang::URI, true);  
   
         string->APPEND_CONST("=");  
   
         Value *value=static_cast<Value *>(avalue);          String attribute(pool);
         string->append(value->as_string(), String::Untaint_lang::URI, true);          SAPI::add_header_attribute(pool,
                   attribute.append(aattribute, String::UL_HEADER, true).cstr(), 
                   attributed_meaning_to_string(lmeaning).cstr());
 }  }
 static void output_response_attribute(const Hash::Key& akey, Hash::Value *ameaning,   
                                                                           void *info) {  
         String *key_to_exclude=static_cast<String *>(info);  
         if(akey==*key_to_exclude)  
                 return;  
   
         String key(akey.pool());  
         key.append(akey, String::Untaint_lang::URI, true);  
   
         Value *meaning=static_cast<Value *>(ameaning);  /**
         String string(meaning->pool());          load MAIN class, execute @main.
         if(VHash *vhash=meaning->get_hash()) {          MAIN class consists of all the auto.p files we'd manage to find
                 // $value(value) $subattribute(subattribute value)          plus
                 Hash& hash=vhash->hash();          the file user requested us to process
           all located classes become children of one another,
                 Value *value=static_cast<Value *>(hash.get(*value_name));          composing class we name 'MAIN'
                 if(value)  */
                         string.append(value->as_string(), String::Untaint_lang::URI, true);  void Request::core(const char *root_auto_path, bool root_auto_fail,
                                      const char *site_auto_path, bool site_auto_fail,
                 hash.foreach(append_attribute_subattribute, &string);                                     bool header_only) {
         } else // string value  
                 string.append(meaning->as_string(), String::Untaint_lang::URI, true);  
   
         (*service_funcs.output_header_attribute)(  
                 key.cstr(),   
                 string.cstr());  
 }  
   
 void Request::core(Exception& system_exception,  
                                    const char *sys_auto_path1,  
                                    const char *sys_auto_path2) {  
         VStateless_class *main_class=0;          VStateless_class *main_class=0;
         bool need_rethrow=false;  Exception rethrow_me;          bool need_rethrow=false;  Exception rethrow_me;
         TRY {          TRY {
                 char *auto_filespec=(char *)malloc(MAX_STRING);                  char *auto_filespec=(char *)malloc(MAX_STRING);
                                   
                 // load MAIN class,                  // loading root auto.p 
                 //      it consists of all the auto.p files we'd manage to find                  if(root_auto_path) {
                 //      plus                          String& filespec=*NEW String(pool());
                 //      the file user requested us to process                          filespec.APPEND_CLEAN(root_auto_path, 0, "root_auto", 0);
                 //      all located classes become children of one another,                          filespec.APPEND_CONST("/" AUTO_FILE_NAME);
                 //      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(                          main_class=use_file(
                                 auto_filespec, false/*ignore possible read problem*/,                                  filespec, root_auto_fail,
                                 main_class_name, main_class);                                  main_class_name, main_class);
                 }                  }
   
                 // loading system auto.p 2                  // $MAIN:LIMITS hash used here,
                 if(sys_auto_path2) {                  //      until someone with less privileges have overriden them
                         strncpy(auto_filespec, sys_auto_path2, MAX_STRING-strlen(AUTO_FILE_NAME));                  {
                         strcat(auto_filespec, AUTO_FILE_NAME);                          Value *limits=main_class?main_class->get_element(*limits_name):0;
                           // $limits.post_max_size default 10M
                           Value *element=limits?limits->get_element(*post_max_size_name):0;
                           size_t value=element?(size_t)element->as_double():0;
                           size_t post_max_size=value?value:MAX_POST_SIZE_DEFAULT;
                           
                           form.fill_fields(*this, post_max_size);
                   }
   
                   // filling cookies
                   cookie.fill_fields(*this);
   
                   // loading site auto.p
                   if(site_auto_path) {
                           String& filespec=*NEW String(pool());
                           filespec.APPEND_CLEAN(site_auto_path, 0, "site_auto", 0);
                           filespec.APPEND_CONST("/" AUTO_FILE_NAME);
                         main_class=use_file(                          main_class=use_file(
                                 auto_filespec, false/*ignore possible read problem*/,                                  filespec, site_auto_fail,
                                 main_class_name, main_class);                                  main_class_name, main_class);
                 }                  }
   
                 Value *element;                  // loading auto.p files from document_root/.. 
                 // $MAIN:limits hash used here,                  // to the one beside requested file.
                 //      until someone with less privileges have overriden them                  // all assigned bases from upper dir
                 Value *limits=main_class?main_class->get_element(*limits_name):0;                  {
                 // $limits.post_max_size default 10M                          /* /document/root */
                 element=limits?limits->get_element(*post_max_size_name):0;                          char *file_spec=
                 int value=element?(size_t)element->get_double():0;                                  (char *)malloc(strlen(info.path_translated)+strlen(AUTO_FILE_NAME)+1);
                 int post_max_size=value?value:10*0x400*400;                          size_t document_root_size=strlen(info.document_root);
                           if(info.document_root[document_root_size-1]=='/')
                 form.fill_fields(*this, post_max_size);                                  document_root_size--;
                           memcpy(file_spec, info.document_root, document_root_size);
                 // TODO: load site auto.p files, all assigned bases from upper dir  
                 /*char *site_auto_file="Y:\\parser3\\src\\auto.p";                          /* /requested/file.html */
                 main_class=use_file(                          char *branches=(char *)malloc(strlen(info.path_translated)+1);
                         site_auto_file, false/*ignore possible read problem* /,                          strcpy(branches, info.path_translated+document_root_size);
                         main_class_name, main_class);*/                          char *next=branches;
                           char *append_here=file_spec+document_root_size;
                 // $MAIN:defaults  
                 Value *defaults=main_class?main_class->get_element(*defaults_name):0;                          size_t slash_auto_p_size=strlen("/" AUTO_FILE_NAME);
                 // $defaults.content-type                          while(true) {
                 if(fdefault_content_type=defaults?defaults->get_element(*content_type_name):0)                                  char *step=lsplit(&next, '/');
                         response.fields().put(*content_type_name, fdefault_content_type);                                  if(next) { // not 'file.html' part
                                           size_t step_size=strlen(step);
                 // there must be some auto.p                                          memcpy(append_here, step, step_size);
                 if(!main_class)                                          append_here+=step_size;
                         THROW(0,0,                                          memcpy(append_here, "/" AUTO_FILE_NAME, slash_auto_p_size+1);
                                 0,                                          append_here++/* / */;
                                 "no 'auto.p' found (nither system nor any site's)");  
                                           String& sfile_spec=*NEW String(pool());
                                           sfile_spec.APPEND_CLEAN(file_spec, 0, "scanned", 0);
                                           main_class=use_file(sfile_spec, false/*ignore read problem*/,
                                                   main_class_name, main_class);
                                   } else
                                           break;
                           }
                   }
   
                 // compiling requested file                  // compiling requested file
                 main_class=use_file(info.path_translated, true/*don't ignore read problem*/,                  String& spath_translated=*NEW String(pool());
                   spath_translated.APPEND_CLEAN(info.path_translated, 0, "user-request", 0);
                   main_class=use_file(spath_translated, true/*don't ignore read problem*/,
                         main_class_name, main_class);                          main_class_name, main_class);
   
                   // $MAIN:DEFAULTS
                   Value *defaults=main_class->get_element(*defaults_name);
                   // value must be allocated on request's pool for that pool used on
                   // meaning constructing @see attributed_meaning_to_string
                   default_content_type=defaults?defaults->get_element(*content_type_name):0;
                   if(Value *element=main_class->get_element(*html_typo_name))
                           if(Table *table=element->get_table())
                                   pool().set_tag(table);
   
                   // $MAIN:MIME-TYPES
                   if(Value *element=main_class->get_element(*mime_types_name))
                           if(Table *table=element->get_table())
                                   mime_types=table;                       
   
                 // execute @main[]                  // execute @main[]
                 const String *body_string=execute_method(*main_class, *main_method_name);                  const String *body_string=execute_method(*main_class, *main_method_name);
                 if(!body_string)                  if(!body_string)
Line 170  void Request::core(Exception& system_exc Line 206  void Request::core(Exception& system_exc
                         0,                           0, 
                         "'"MAIN_METHOD_NAME"' method not found");                          "'"MAIN_METHOD_NAME"' method not found");
   
                   VString body_vstring_before_post_process(*body_string);
                   VString *body_vstring_after_post_process=&body_vstring_before_post_process;
                   
                   // post-process
                   if(Value *value=main_class->get_element(*post_process_method_name))
                           if(Junction *junction=value->get_junction())
                                   if(const Method *method=junction->method) {
                                           // preparing to pass parameters to 
                                           //      @post-process[data]
                                           VMethodFrame frame(pool(), *junction);
                                           frame.set_self(*main_class);
   
                                           frame.store_param(method->name, 
                                                   &body_vstring_before_post_process);
                                           body_vstring_after_post_process=
                                                   NEW VString(*execute_method(frame, *method));
                                   }
   
                   const VFile *body_file=body_vstring_after_post_process->as_vfile();
   
                 // extract response body                  // extract response body
                 Value *body_value=static_cast<Value *>(                  Value *body_value=static_cast<Value *>(
                         response.fields().get(*body_name));                          response.fields().get(*body_name));
                 if(body_value) // there is some $request.body                  if(body_value) // there is some $request.body
                         body_string=&body_value->as_string();// TODO: IMAGE&FILE                          body_file=body_value->as_vfile();
   
                 // OK. write out the result                  // OK. write out the result
                 output_result(*body_string);                  output_result(*body_file, header_only);
         }           } 
         CATCH(e) {          CATCH(e) { // request handling problem
                   // we're returning not result, but error explanation
                 TRY {                  TRY {
                         // we're returning not result, but error explanation                          // log the beast
                           const String *problem_source=e.problem_source();
                           if(problem_source)
                                   SAPI::log(pool(),
   #ifndef NO_STRING_ORIGIN
                                           "%s(%d): "
   #endif
                                           "'%s' %s [%s %s]",
   #ifndef NO_STRING_ORIGIN
                                           problem_source->origin().file?problem_source->origin().file:"global",
                                           problem_source->origin().line,
   #endif
                                           problem_source->cstr(),
                                           e.comment(),
                                           e.type()?e.type()->cstr():"-",
                                           e.code()?e.code()->cstr():"-"
                                   );
                           else
                                   SAPI::log(pool(),
                                           "%s [%s %s]",
                                           e.comment(),
                                           e.type()?e.type()->cstr():"-",
                                           e.code()?e.code()->cstr():"-"
                                           );
   
                         // reset language to default                          // reset language to default
                         flang=fdefault_lang;                          flang=fdefault_lang;
Line 189  void Request::core(Exception& system_exc Line 269  void Request::core(Exception& system_exc
                         // reset response                          // reset response
                         response.fields().clear();                          response.fields().clear();
   
                         // this is what we'd return in $response:content-type  
                         Value *content_type;  
   
                         // this is what we'd return in $response:body                          // this is what we'd return in $response:body
                         const String *body_string=0;                          const String *body_string=0;
   
Line 208  void Request::core(Exception& system_exc Line 285  void Request::core(Exception& system_exc
   
                                                         const String *problem_source=e.problem_source();                                                          const String *problem_source=e.problem_source();
                                                         // origin                                                          // origin
                                                         String origin_name(pool(), "origin");  
                                                         Value *origin_value=0;                                                          Value *origin_value=0;
 #ifndef NO_STRING_ORIGIN  #ifndef NO_STRING_ORIGIN
                                                         if(problem_source) {                                                          if(problem_source) {
Line 223  void Request::core(Exception& system_exc Line 299  void Request::core(Exception& system_exc
                                                                 }                                                                  }
                                                         }                                                          }
 #endif  #endif
                                                         frame.store_param(origin_name,                                                           frame.store_param(method->name, 
                                                                 origin_value?origin_value:NEW VUnknown(pool()));                                                                  origin_value?origin_value:NEW VUnknown(pool()));
   
                                                         // source                                                          // source
                                                         String source_name(pool(), "source");  
                                                         Value *source_value=0;                                                          Value *source_value=0;
                                                         if(problem_source) {                                                          if(problem_source) {
                                                                 String& problem_source_copy=*NEW String(pool());                                                                  String& problem_source_copy=*NEW String(pool());
Line 235  void Request::core(Exception& system_exc Line 310  void Request::core(Exception& system_exc
                                                                         flang, true);                                                                          flang, true);
                                                                 source_value=NEW VString(problem_source_copy);                                                                  source_value=NEW VString(problem_source_copy);
                                                         }                                                          }
                                                         frame.store_param(source_name,                                                           frame.store_param(method->name, 
                                                                 source_value?source_value:NEW VUnknown(pool()));                                                                  source_value?source_value:NEW VUnknown(pool()));
   
                                                         // comment                                                          // comment
                                                         String comment_name(pool(), "comment");  
                                                         String *comment_value=NEW String(pool(),                                                          String *comment_value=NEW String(pool(),
                                                                 e.comment(), true);                                                                  e.comment(), true);
                                                         frame.store_param(comment_name,                                                           frame.store_param(method->name, 
                                                                 NEW VString(*comment_value));                                                                  NEW VString(*comment_value));
   
                                                         // type                                                          // type
                                                         String type_name(pool(), "type");  
                                                         Value *type_value;                                                          Value *type_value;
                                                         if(e.type()) {                                                          if(e.type()) {
                                                                 String& type_copy=*NEW String(pool());                                                                  String& type_copy=*NEW String(pool());
Line 254  void Request::core(Exception& system_exc Line 327  void Request::core(Exception& system_exc
                                                                         flang, true));                                                                          flang, true));
                                                         } else                                                          } else
                                                                 type_value=NEW VUnknown(pool());                                                                  type_value=NEW VUnknown(pool());
                                                         frame.store_param(type_name, type_value);                                                          frame.store_param(method->name, type_value);
   
                                                         // code                                                          // code
                                                         String code_name(pool(), "code");  
                                                         Value *code_value;                                                          Value *code_value;
                                                         if(e.code()) {                                                          if(e.code()) {
                                                                 String& code_copy=*NEW String(pool());                                                                  String& code_copy=*NEW String(pool());
Line 265  void Request::core(Exception& system_exc Line 337  void Request::core(Exception& system_exc
                                                                         flang, true));                                                                          flang, true));
                                                         } else                                                          } else
                                                                 code_value=NEW VUnknown(pool());                                                                  code_value=NEW VUnknown(pool());
                                                         frame.store_param(code_name, code_value);                                                          frame.store_param(method->name, code_value);
   
                                                         // future $response:content-type=  
                                                         //   content-type from any auto.p  
                                                         content_type=fdefault_content_type;  
                                                         // future $response:body=                                                          // future $response:body=
                                                         //   execute ^exception[origin;source;comment;type;code]                                                          //   execute ^exception[origin;source;comment;type;code]
                                                         body_string=execute_method(frame, *method);                                                          body_string=execute_method(frame, *method);
Line 306  void Request::core(Exception& system_exc Line 375  void Request::core(Exception& system_exc
                                 }                                  }
   
                                 // future $response:content-type                                  // future $response:content-type
                                 String &content_type_value=*NEW String(pool(), "text/plain");                                  response.fields().put(*content_type_name, 
                                 content_type=NEW VString(content_type_value);                                          NEW VString(*NEW String(pool(), UNHANDLED_EXCEPTION_CONTENT_TYPE)));
                                 // future $response:body                                  // future $response:body
                                 body_string=NEW String(pool(), buf);                                  body_string=NEW String(pool(), buf);
                         }                          }
   
                         // set $response:content-type                          const VString body_vstring(*body_string);
                         if(content_type)                          const VFile *body_file=body_vstring.as_vfile();
                                 response.fields().put(*content_type_name, content_type);  
   
                         // ERROR. write it out                          // ERROR. write it out
                         output_result(*body_string);                          output_result(*body_file, header_only);
                 }                  }
                 CATCH(e) {                  CATCH(e) {
                         // exception in request exception handler                          // exception in request exception handler
Line 329  void Request::core(Exception& system_exc Line 397  void Request::core(Exception& system_exc
         END_CATCH // do not use pool() after this point - no exception handler set          END_CATCH // do not use pool() after this point - no exception handler set
                   // any throw() would try to use zero exception() pointer                     // any throw() would try to use zero exception() pointer 
   
         if(need_rethrow) // there were an exception set for us to rethrow?          if(need_rethrow) // were there an exception for us to rethrow?
                 system_exception._throw(rethrow_me.type(), rethrow_me.code(),                  THROW(rethrow_me.type(), rethrow_me.code(),
                         rethrow_me.problem_source(),                          rethrow_me.problem_source(),
                         rethrow_me.comment());                          rethrow_me.comment());
   
 }  }
   
 VStateless_class *Request::use_file(  VStateless_class *Request::use_file(const String& file_spec, bool fail_on_read_problem,
                                                                         const char *file, bool fail_on_read_problem,  
                                                                         const String *name,                                                                           const String *name, 
                                                                         VStateless_class *base_class) {                                                                          VStateless_class *base_class) {
         // TODO: обнаружить|решить cyclic dependences          // cyclic dependence check
         char *source=file_read(pool(), file, fail_on_read_problem);          if(used_files.get(file_spec))
                   return base_class;
           used_files.put(file_spec, (Hash::Val *)true);
   
   
           char *source=file_read_text(pool(), file_spec, fail_on_read_problem);
         if(!source)          if(!source)
                 return base_class;                  return base_class;
   
         return use_buf(source, file, 0/*new class*/, name, base_class);          return use_buf(source, file_spec.cstr(), 0/*new class*/, name, base_class);
 }  }
   
 VStateless_class *Request::use_buf(  VStateless_class *Request::use_buf(const char *source, const char *file,
                                                                    const char *source, const char *file,  
                                                                    VStateless_class *aclass, const String *name,                                                                      VStateless_class *aclass, const String *name, 
                                                                    VStateless_class *base_class) {                                                                     VStateless_class *base_class) {
         // compile loaded class          // compile loaded class
Line 360  VStateless_class *Request::use_buf( Line 431  VStateless_class *Request::use_buf(
         return &cclass;          return &cclass;
 }  }
   
 void Request::fail_if_junction_(bool is,   /**
                                                                 Value& value, const String& method_name, char *msg) {          - fail_if_junction(true, junction = fail
           - fail_if_junction(false, not junction = fail
   */
   void Request::fail_if_junction_(bool is, Value& value, 
                                                                   const String& method_name, const char *msg) {
   
         // fail_if_junction(true, junction = fail  
         // fail_if_junction(false, not junction = fail  
         if((value.get_junction()!=0) ^ !is)          if((value.get_junction()!=0) ^ !is)
                 THROW(0, 0,                  THROW(0, 0,
                         &method_name,                          &method_name,
                         msg);                          msg);
 }  }
   
 char *Request::relative(const char *path, const char *file) {  const String& Request::relative(const char *apath, const String& relative_name) {
     char *result=(char *)malloc(strlen(path)+strlen(file)+1);          int lpath_buf_size=strlen(apath)+1;
         strcpy(result, path);      char *lpath=(char *)malloc(lpath_buf_size);
     rsplit(result, PATH_DELIMITER_CHAR);          memcpy(lpath, apath, lpath_buf_size);
     strcat(result, PATH_DELIMITER_STRING);      rsplit(lpath, '/');
     strcat(result, file);          String& result=*NEW String(pool(), lpath);
       result.APPEND_CONST("/");
           result.append(relative_name, String::UL_PASS_APPENDED);
     return result;      return result;
 }  }
   
 char *Request::absolute(const char *name) {  const String& Request::absolute(const String& relative_name) {
         if(name[0]=='/') {          char *relative_name_cstr=relative_name.cstr();
                 char *result=(char *)malloc(strlen(info.document_root)+strlen(name)+1);          if(relative_name_cstr[0]=='/') {
                 strcpy(result, info.document_root);                  String& result=*NEW String(pool(), info.document_root);
                 strcat(result, name);                  result.append(relative_name, String::UL_PASS_APPENDED);
                 return result;                  return result;
         } else           } else 
                 return relative(info.uri, name);                  return relative(info.path_translated, relative_name);
 }  }
   
 void Request::output_result(const String& body_string) {  void Request::output_result(const VFile& body_file, bool header_only) {
         // header: response fields           // header: cookies
         response.fields().foreach(output_response_attribute, /*excluding*/ body_name);          cookie.output_result();
         const char *body=body_string.cstr();          
         if(size_t content_length=strlen(body)) {          // set content-type
                 // header: content-length          if(String *body_file_content_type=static_cast<String *>(
                   body_file.fields().get(*vfile_mime_type_name))) {
                   // body file content type
                   response.fields().put(*content_type_name, body_file_content_type);
           } else {
                   // default content type
                   response.fields().put_dont_replace(*content_type_name, 
                           default_content_type?default_content_type
                           :NEW VString(*NEW String(pool(), DEFAULT_CONTENT_TYPE)));
           }
   
           // content-disposition
           if(VString *vfile_name=static_cast<VString *>(body_file.fields().get(*name_name))) {
                   VHash& vhash=*NEW VHash(pool());
                   vhash.hash().put(*content_disposition_filename_name, vfile_name);
                   response.fields().put(*content_disposition_name, &vhash);
           }
   
           // prepare header: $response:fields without :body
           response.fields().for_each(add_header_attribute, /*excluding*/ body_name);
   
           // prepare...
           const void *body=body_file.value_ptr();
           size_t content_length=body_file.value_size();
   
           // prepare header: content-length
           if(content_length) { // useful for redirecting [header "location: http://..."]
                 char content_length_cstr[MAX_NUMBER];                  char content_length_cstr[MAX_NUMBER];
                 snprintf(content_length_cstr, MAX_NUMBER, "%d", content_length);                  snprintf(content_length_cstr, MAX_NUMBER, "%lu", content_length);
                 (*service_funcs.output_header_attribute)("content-length",                   SAPI::add_header_attribute(pool(), "content-length", content_length_cstr);
                         content_length_cstr);  
                 // body  
                 (*service_funcs.output_body)(body, content_length);  
         }          }
 }  
   
   
           // send header
           SAPI::send_header(pool());
           
           // send body
           if(!header_only)
                   SAPI::send_body(pool(), body, content_length);
   }

Removed from v.1.47  
changed lines
  Added in v.1.93


E-mail: