Diff for /parser3/src/main/pa_common.C between versions 1.239 and 1.246

version 1.239, 2009/01/12 07:15:45 version 1.246, 2009/07/06 08:47:10
Line 1 Line 1
 /** @file  /** @file
         Parser: commonly functions.          Parser: commonly functions.
   
         Copyright(c) 2001-2005 ArtLebedev Group (http://www.artlebedev.com)          Copyright(c) 2001-2009 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)
   
  * BASE64 part   * BASE64 part
Line 36  static const char * const IDENT_COMMON_C Line 36  static const char * const IDENT_COMMON_C
 #include "pa_http.h"  #include "pa_http.h"
 #include "pa_request_charsets.h"  #include "pa_request_charsets.h"
 #include "pcre.h"  #include "pcre.h"
   #include "pa_request.h"
   
 // some maybe-undefined constants  // some maybe-undefined constants
   
Line 102  char* file_read_text(Request_charsets& c Line 103  char* file_read_text(Request_charsets& c
         return file.success?file.str:0;          return file.success?file.str:0;
 }  }
   
   char* file_load_text(Request& r, 
                           const String& file_spec, 
                           bool fail_on_read_problem,
                           HashStringValue* params,
                           bool transcode_result) {
           File_read_result file=
                   file_load(r, file_spec, true, params, fail_on_read_problem, 0, 0, 0, transcode_result);
           return file.success?file.str:0;
   }
   
 /// these options were handled but not checked elsewhere, now check them  /// these options were handled but not checked elsewhere, now check them
 int pa_get_valid_file_options_count(HashStringValue& options) {  int pa_get_valid_file_options_count(HashStringValue& options) {
         int result=0;          int result=0;
Line 155  static void file_read_action( Line 166  static void file_read_action(
                 return;                  return;
         }          }
 }  }
   
 File_read_result file_read(Request_charsets& charsets, const String& file_spec,   File_read_result file_read(Request_charsets& charsets, const String& file_spec, 
                         bool as_text, HashStringValue *params,                          bool as_text, HashStringValue *params,
                         bool fail_on_read_problem,                          bool fail_on_read_problem,
                         char* buf, size_t offset, size_t count, bool transcode_text_result) {                          char* buf, size_t offset, size_t count, bool transcode_text_result) {
         File_read_result result={false, 0, 0, 0};          File_read_result result={false, 0, 0, 0};
         if(file_spec.starts_with("http://")) {          if(params){
                 if(offset || count)                  int valid_options=pa_get_valid_file_options_count(*params);
                   if(valid_options!=params->count())
                         throw Exception(PARSER_RUNTIME,                          throw Exception(PARSER_RUNTIME,
                                 0,                                  0,
                                 "offset and load options are not supported for HTTP:// file load");                                  "invalid option passed");
           }
   
                 // fail on read problem          File_read_action_info info={&result.str, &result.length, buf, offset, count}; 
                 File_read_http_result http=pa_internal_file_read_http(charsets, file_spec, as_text, params, transcode_text_result);  
                 result.success=true;  
                 result.str=http.str;  
                 result.length=http.length;  
                 result.headers=http.headers;   
         } else {  
                 if(params){  
                         int valid_options=pa_get_valid_file_options_count(*params);  
                         if(valid_options!=params->count())  
                                 throw Exception(PARSER_RUNTIME,  
                                         0,  
                                         "invalid option passed");  
                 }  
   
                 File_read_action_info info={&result.str, &result.length,          result.success=file_read_action_under_lock(file_spec, 
                         buf, offset, count};                   "read", file_read_action, &info, 
                 result.success=file_read_action_under_lock(file_spec,                   as_text, fail_on_read_problem); 
                         "read", file_read_action, &info,   
                         as_text, fail_on_read_problem);   
   
                 if(as_text && result.success){          if(as_text){
                   if(result.success){
                         if(result.length>=3 && strncmp(result.str, "\xEF\xBB\xBF", 3)==0){                          if(result.length>=3 && strncmp(result.str, "\xEF\xBB\xBF", 3)==0){
                                 // skip UTF-8 signature: EF BB BF  (BOM code)                                  // skip UTF-8 signature (BOM code)
                                 result.str+=3;                                  result.str+=3;
                                 result.length-=3;                                  result.length-=3;
                         }                          }
                                                   
                         if(result.length && transcode_text_result && params){ // must be checked because transcode returns CONST string in case length==0, which contradicts hacking few lines below                          if(result.length && transcode_text_result && params){ // must be checked because transcode returns CONST string in case length==0, which contradicts hacking few lines below
                                 if( Value* vcharset_name=params->get(PA_CHARSET_NAME) ){                                  if(Value* vcharset_name=params->get(PA_CHARSET_NAME)){
                                         Charset asked_charset=::charsets.get(vcharset_name->as_string().                                          Charset asked_charset=::charsets.get(vcharset_name->as_string().
                                                 change_case(charsets.source(), String::CC_UPPER));                                                  change_case(charsets.source(), String::CC_UPPER));
   
Line 207  File_read_result file_read(Request_chars Line 207  File_read_result file_read(Request_chars
                                 }                                  }
                         }                          }
                 }                  }
                   if(result.length)
                           fix_line_breaks(result.str, result.length);
         }          }
           
         if(as_text && result.length)          return result;
                 fix_line_breaks(result.str, result.length);  }
   
   File_read_result file_load(Request& r, const String& file_spec, 
                           bool as_text, HashStringValue *params,
                           bool fail_on_read_problem,
                           char* buf, size_t offset, size_t count, bool transcode_text_result) {
   
           File_read_result result={false, 0, 0, 0};
           if(file_spec.starts_with("http://")) {
                   if(offset || count)
                           throw Exception(PARSER_RUNTIME,
                                   0,
                                   "offset and load options are not supported for HTTP:// file load");
   
                   // fail on read problem
                   File_read_http_result http=pa_internal_file_read_http(r, file_spec, as_text, params, transcode_text_result);
                   result.success=true;
                   result.str=http.str;
                   result.length=http.length;
                   result.headers=http.headers; 
           } else
                   result=
                           file_read(r.charsets, file_spec, as_text, params, fail_on_read_problem, buf, offset, count, transcode_text_result);
   
         return result;          return result;
 }  }
Line 236  bool file_read_action_under_lock(const S Line 260  bool file_read_action_under_lock(const S
                                 const char* action_name, File_read_action action, void *context,                                   const char* action_name, File_read_action action, void *context, 
                                 bool as_text,                                   bool as_text, 
                                 bool fail_on_read_problem) {                                  bool fail_on_read_problem) {
         const char* fname=file_spec.cstr(String::L_FILE_SPEC);           const char* fname=file_spec.cstr_taint(String::L_FILE_SPEC); 
         int f;          int f;
   
         // first open, next stat:          // first open, next stat:
Line 291  void create_dir_for_file(const String& f Line 315  void create_dir_for_file(const String& f
         size_t pos_after=1;          size_t pos_after=1;
         size_t pos_before;          size_t pos_before;
         while((pos_before=file_spec.pos('/', pos_after))!=STRING_NOT_FOUND) {          while((pos_before=file_spec.pos('/', pos_after))!=STRING_NOT_FOUND) {
                 mkdir(file_spec.mid(0, pos_before).cstr(String::L_FILE_SPEC), 0775);                   mkdir(file_spec.mid(0, pos_before).cstr_taint(String::L_FILE_SPEC), 0775); 
                 pos_after=pos_before+1;                  pos_after=pos_before+1;
         }          }
 }  }
Line 305  bool file_write_action_under_lock( Line 329  bool file_write_action_under_lock(
                                 bool do_append,                                   bool do_append, 
                                 bool do_block,                                   bool do_block, 
                                 bool fail_on_lock_problem) {                                  bool fail_on_lock_problem) {
         const char* fname=file_spec.cstr(String::L_FILE_SPEC);           const char* fname=file_spec.cstr_taint(String::L_FILE_SPEC); 
         int f;          int f;
         if(access(fname, W_OK)!=0) // no          if(access(fname, W_OK)!=0) // no
                 create_dir_for_file(file_spec);                   create_dir_for_file(file_spec); 
Line 387  static void rmdir(const String& file_spe Line 411  static void rmdir(const String& file_spe
         if((pos_before=file_spec.pos('/', pos_after))!=STRING_NOT_FOUND)          if((pos_before=file_spec.pos('/', pos_after))!=STRING_NOT_FOUND)
                 rmdir(file_spec, pos_before+1);                   rmdir(file_spec, pos_before+1); 
                   
         rmdir(file_spec.mid(0, pos_after-1/* / */).cstr(String::L_FILE_SPEC));           rmdir(file_spec.mid(0, pos_after-1/* / */).cstr_taint(String::L_FILE_SPEC)); 
 }  }
   
 bool file_delete(const String& file_spec, bool fail_on_problem) {  bool file_delete(const String& file_spec, bool fail_on_problem) {
         const char* fname=file_spec.cstr(String::L_FILE_SPEC);           const char* fname=file_spec.cstr_taint(String::L_FILE_SPEC); 
         if(unlink(fname)!=0)          if(unlink(fname)!=0)
                 if(fail_on_problem)                  if(fail_on_problem)
                         throw Exception(errno==EACCES?"file.access":errno==ENOENT?"file.missing":0,                           throw Exception(errno==EACCES?"file.access":errno==ENOENT?"file.missing":0, 
Line 406  bool file_delete(const String& file_spec Line 430  bool file_delete(const String& file_spec
 }  }
   
 void file_move(const String& old_spec, const String& new_spec) {  void file_move(const String& old_spec, const String& new_spec) {
         const char* old_spec_cstr=old_spec.cstr(String::L_FILE_SPEC);           const char* old_spec_cstr=old_spec.cstr_taint(String::L_FILE_SPEC); 
         const char* new_spec_cstr=new_spec.cstr(String::L_FILE_SPEC);           const char* new_spec_cstr=new_spec.cstr_taint(String::L_FILE_SPEC); 
                   
         create_dir_for_file(new_spec);           create_dir_for_file(new_spec); 
   
Line 430  bool entry_exists(const char* fname, str Line 454  bool entry_exists(const char* fname, str
 }  }
   
 bool entry_exists(const String& file_spec) {  bool entry_exists(const String& file_spec) {
         const char* fname=file_spec.cstr(String::L_FILE_SPEC);           const char* fname=file_spec.cstr_taint(String::L_FILE_SPEC); 
         return entry_exists(fname, 0);           return entry_exists(fname, 0); 
 }  }
   
 static bool entry_readable(const String& file_spec, bool need_dir) {  static bool entry_readable(const String& file_spec, bool need_dir) {
         char* fname=file_spec.cstrm(String::L_FILE_SPEC);           char* fname=file_spec.cstrm_taint(String::L_FILE_SPEC); 
         if(need_dir) {          if(need_dir) {
                 size_t size=strlen(fname);                   size_t size=strlen(fname); 
                 while(size) {                  while(size) {
Line 470  const String* file_exist(const String& p Line 494  const String* file_exist(const String& p
 }  }
   
 bool file_executable(const String& file_spec) {  bool file_executable(const String& file_spec) {
         return access(file_spec.cstr(String::L_FILE_SPEC), X_OK)==0;          return access(file_spec.cstr_taint(String::L_FILE_SPEC), X_OK)==0;
 }  }
   
 bool file_stat(const String& file_spec,   bool file_stat(const String& file_spec, 
Line 479  bool file_stat(const String& file_spec, Line 503  bool file_stat(const String& file_spec,
                         time_t& rmtime,                          time_t& rmtime,
                         time_t& rctime,                          time_t& rctime,
                         bool fail_on_read_problem) {                          bool fail_on_read_problem) {
         const char* fname=file_spec.cstr(String::L_FILE_SPEC);           const char* fname=file_spec.cstr_taint(String::L_FILE_SPEC); 
         struct stat finfo;          struct stat finfo;
         if(stat(fname, &finfo)!=0)          if(stat(fname, &finfo)!=0)
                 if(fail_on_read_problem)                  if(fail_on_read_problem)
Line 770  size_t strpos(const char *str, const cha Line 794  size_t strpos(const char *str, const cha
 // content-type: xxx; charset=WE-NEED-THIS  // content-type: xxx; charset=WE-NEED-THIS
 // content-type: xxx; charset="WE-NEED-THIS"  // content-type: xxx; charset="WE-NEED-THIS"
 // content-type: xxx; charset="WE-NEED-THIS";  // content-type: xxx; charset="WE-NEED-THIS";
 Charset* detect_charset(const char* content_type){  Charset* detect_charset(const char* content_type, bool already_uppercased){
         if(content_type){          if(content_type){
                 size_t len=strlen(content_type);                  char* CONTENT_TYPE=pa_strdup(content_type);
                 char* CONTENT_TYPE=new(PointerFreeGC) char[len+1];                  if(!already_uppercased)
                 memcpy(CONTENT_TYPE, content_type, len);                          for(char *p=CONTENT_TYPE; *p; p++)
                 for(char *p=CONTENT_TYPE; *p; p++)                                  *p=(char)toupper((unsigned char)*p);
                         *p=(char)toupper((unsigned char)*p);  
   
                 if(const char* begin=strstr(CONTENT_TYPE, "CHARSET=")){                  if(const char* begin=strstr(CONTENT_TYPE, "CHARSET=")){
                         begin+=8; // skip "CHARSET="                          begin+=8; // skip "CHARSET="
Line 789  Charset* detect_charset(const char* cont Line 812  Charset* detect_charset(const char* cont
                         if(!end)                          if(!end)
                                 end=(char*)strchr(begin, ';');                                  end=(char*)strchr(begin, ';');
   
                         size_t len;                          if(end)
                         if(end){  
                                 *end=0; // terminator                                  *end=0; // terminator
                                 len=end-begin;  
                         } else {  
                                 len=strlen(begin);  
                         }  
   
                         String::Body NAME=String::Body(begin, len);                          return *begin?&charsets.get(begin):0;
                         return &charsets.get(NAME);  
                 }                  }
         }          }
         return 0;          return 0;
 }  }
   
 Charset* detect_charset(Charset& source_charset, const String& content_type){  
         const String& CONTENT_TYPE=content_type.change_case(source_charset, String::CC_UPPER);  
         size_t begin=CONTENT_TYPE.pos("CHARSET=");  
         if(begin!=STRING_NOT_FOUND) {  
                 begin+=8; // skip "CHARSET="  
                 size_t end=STRING_NOT_FOUND;  
   
                 if(CONTENT_TYPE.pos('"', begin)==begin){  
                         begin++;  
                         end=CONTENT_TYPE.pos('"', begin);  
                 } else if(CONTENT_TYPE.pos('\'', begin)==begin){  
                         begin++;  
                         end=CONTENT_TYPE.pos('\'', begin);  
                 }  
   
                 if(end==STRING_NOT_FOUND)  
                         end=CONTENT_TYPE.pos(';', begin);  
   
                 if(end==STRING_NOT_FOUND)  
                         end=CONTENT_TYPE.length();  
   
                 const String::Body NAME=CONTENT_TYPE.mid(begin, end);  
                 return &charsets.get(NAME);  
         }  
         return 0;  
 }  
   
   
 static bool isLeap(int year) {  static bool isLeap(int year) {
         return !(          return !(
Line 933  int __vsnprintf(char* b, size_t s, const Line 923  int __vsnprintf(char* b, size_t s, const
   
 int __snprintf(char* b, size_t s, const char* f, ...) {  int __snprintf(char* b, size_t s, const char* f, ...) {
         va_list l;          va_list l;
     va_start(l, f);           va_start(l, f); 
     int r=__vsnprintf(b, s, f, l);           int r=__vsnprintf(b, s, f, l); 
     va_end(l);           va_end(l); 
         return r;          return r;
 }  }
   
Line 1258  int file_block_read(const int f, unsigne Line 1248  int file_block_read(const int f, unsigne
 const unsigned long pa_crc32(const char *in, size_t in_size){  const unsigned long pa_crc32(const char *in, size_t in_size){
         unsigned long crc32=0xFFFFFFFF;          unsigned long crc32=0xFFFFFFFF;
   
                 InitCrc32Table();          InitCrc32Table();
         for(size_t i = 0; i<in_size; i++)          for(size_t i = 0; i<in_size; i++)
                 CalcCrc32(in[i], crc32);                  CalcCrc32(in[i], crc32);
   
Line 1288  static void file_crc32_file_action( Line 1278  static void file_crc32_file_action(
         }          }
 }  }
   
 char* print_pcre_exec_error_text(int exec_result){  
         switch(exec_result){  
                 case PCRE_ERROR_BADUTF8:  
                         return "validation of UTF-8 string failed while pcre_exec (%d).";  
                         break;  
                 default:  
                         return "regular expression execute error (%d)";  
         }  
 }  
   

Removed from v.1.239  
changed lines
  Added in v.1.246


E-mail: