Diff for /parser3/src/main/pa_common.C between versions 1.202 and 1.209

version 1.202, 2004/12/23 15:01:03 version 1.209, 2005/11/18 10:17:39
Line 1 Line 1
 /** @file  /** @file
         Parser: commonly functions.          Parser: commonly functions.
   
         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 131  char* file_read_text(Request_charsets& c Line 131  char* file_read_text(Request_charsets& c
         return file.success?file.str:0;          return file.success?file.str:0;
 }  }
   
   /// these options were handled but not checked elsewhere, now check them
   static int get_valid_file_options_count(HashStringValue& options)
   {
           int result=0;
           if(options.get(PA_SQL_LIMIT_NAME))
                   result++;
           if(options.get(PA_SQL_OFFSET_NAME))
                   result++;
           if(options.get(PA_COLUMN_SEPARATOR_NAME))
                   result++;
           if(options.get(PA_COLUMN_ENCLOSER_NAME))
                   result++;
           return result;
   }
   
 //http request stuff  //http request stuff
 #ifdef PA_HTTP  #ifdef PA_HTTP
   
Line 157  static bool set_addr(struct sockaddr_in Line 172  static bool set_addr(struct sockaddr_in
     return true;      return true;
 }  }
   
 static int http_read_response(char*& response, size_t& response_size, int sock, bool fail_on_status_ne_200){  size_t guess_content_length(char* buf) {
         response=(char*)pa_malloc_atomic(1/*terminator*/); // setting memory block type          char* ptr;
         response[(response_size=0)]=0;          if((ptr=strstr(buf, "Content-Length:"))) // Apache
                   goto found;
           if((ptr=strstr(buf, "content-length:"))) // Parser 3
                   goto found;
           if((ptr=strstr(buf, "Content-length:"))) // maybe 1
                   goto found;
           if((ptr=strstr(buf, "CONTENT-LENGTH:"))) // maybe 2
                   goto found;
           return 0;
   found:
           char *error_pos;
           size_t result=(size_t)strtol(ptr+15/*strlen("CONTENT-LENGTH:")*/, &error_pos, 0);
           
           const size_t reasonable_initial_max=0x400*0x400*10 /*10M*/;
           if(result>reasonable_initial_max) // sanity check
                   return reasonable_initial_max;
           return 0;//result;
   }
   
   static int http_read_response(char*& response, size_t& response_size, int sock, bool fail_on_status_ne_200) {
         int result=0;          int result=0;
         char* EOLat=0;          // fetching some to local buffer, guessing on possible content-length   
         while(true) {          response_size=0x400*20; // initial size if content-length could not be determined       
                 char buf[MAX_STRING*10];           const size_t preview_size=0x400*20;
                 ssize_t received_size=recv(sock, buf, sizeof(buf), 0);           char preview_buf[preview_size+1/*terminator*/];  // 20K buffer to preview headers
                 if(received_size<=0) {          ssize_t received_size=recv(sock, preview_buf, preview_size, 0); 
                         if(int no=pa_socks_errno())          if(received_size==0)
                                 throw Exception("http.timeout",                   goto done;
                                         0,           if(received_size<0) {
                                         "error receiving response: %s (%d)", pa_socks_strerr(no), no);                   if(int no=pa_socks_errno())
                         break;                          throw Exception("http.timeout", 
                 }                                  0, 
                 response=(char*)pa_realloc(response, response_size+received_size+1/*terminator*/);                                  "error receiving response header: %s (%d)", pa_socks_strerr(no), no); 
                 memcpy(response+response_size, buf, received_size);                  goto done;
                 response_size+=received_size;          }
                 response[response_size]=0;          // detecting response_size
           {
                   preview_buf[received_size]=0; // terminator
                   if(size_t content_length=guess_content_length(preview_buf))
                           response_size=preview_size+content_length; // a little more than needed, will adjust response_size by actual received size later
           }
   
                 if(!result && (EOLat=strstr(response, "\n"))) { // checking status in first response          // [gcc is happier this way, see goto above]
                         const String status_line(pa_strdup(response, EOLat-response));          {
                         ArrayString astatus;                   // allocating initial buf
                         size_t pos_after=0;                  response=(char*)pa_malloc_atomic(response_size+1/*terminator*/); // just setting memory block type
                         status_line.split(astatus, pos_after, " ");                   char* ptr=response;
                         const String& status_code=*astatus.get(astatus.count()>1?1:0);                  size_t todo_size=response_size;
                         result=status_code.as_int();                   // coping part of already received body
                   memcpy(ptr, preview_buf, received_size);
                         if(fail_on_status_ne_200 && result!=200)                  ptr+=received_size;
                                 throw Exception("http.status",                  todo_size-=received_size;               
                                         &status_code,  
                                         "invalid HTTP response status");                  // we use terminator byte for two purposes here:
                   // 1. we return there zero always, not knowing: maybe they would want to create String form $file.body?
                   //     invariant: all Strings should have zero-terminated buffers
                   // 2. we use that out-of-size byte to detect if our content-length guess was wrong
                   //    when recv gets more than we expected
                   //    a) we know that the content-length guess was wrong
                   //    b) we have space to put the first byte of extra data
                   //    c) we use less code to detect normal situation: on last while-cycle recv expected to just return 0
                   while(true) {
                           received_size=recv(sock, ptr, todo_size+1/*there is always a place for terminator*/, 0); 
                           if(received_size==0) {
                                   response_size-=todo_size; // in case we received less than expected, cut down the reported size
                                   break;
                           }
                           if(received_size<0) {
                                   if(int no=pa_socks_errno())
                                           throw Exception("http.timeout", 
                                                   0, 
                                                   "error receiving response body: %s (%d)", pa_socks_strerr(no), no); 
                                   break;
                           }
                           // they've touched the terminator?
                           if((size_t)received_size>todo_size)
                           {
                                   // that means that our guessed response_size was not big enough
                                   const size_t grow_chunk_size=0x400*0x400; // 1M
                                   response_size+=grow_chunk_size;
                                   size_t ptr_offset=ptr-response;
                                   response=(char*)pa_realloc(response, response_size+1/*terminator*/);
                                   ptr=response+ptr_offset;
                                   todo_size+=grow_chunk_size;
                           }
                           // can't do this before realloc: we need <todo_size check
                           ptr+=received_size;
                           todo_size-=received_size;
   
                           char* EOLat=0;
                           if(!result && (EOLat=strstr(response, "\n"))) { // checking status in first response
                                   const String status_line(pa_strdup(response, EOLat-response));
                                   ArrayString astatus; 
                                   size_t pos_after=0;
                                   status_line.split(astatus, pos_after, " "); 
                                   const String& status_code=*astatus.get(astatus.count()>1?1:0);
                                   result=status_code.as_int(); 
   
                                   if(fail_on_status_ne_200 && result!=200)
                                           throw Exception("http.status",
                                                   &status_code,
                                                   "invalid HTTP response status");
                           }
                 }                  }
         }          }
   done:
         if(result)          if(result)
           {
                   response[response_size]=0;
                 return result;                  return result;
           }
         else          else
                 throw Exception("http.response",                  throw Exception("http.response",
                         0,                          0,
Line 456  static File_read_http_result file_read_h Line 548  static File_read_http_result file_read_h
         const char* password_cstr=0;          const char* password_cstr=0;
   
         if(options) {          if(options) {
                 int valid_options=0;                  int valid_options=get_valid_file_options_count(*options);
   
                 if(Value* vmethod=options->get(HTTP_METHOD_NAME)) {                  if(Value* vmethod=options->get(HTTP_METHOD_NAME)) {
                         valid_options++;                          valid_options++;
                         method=vmethod->as_string().cstr();                          method=vmethod->as_string().cstr();
Line 717  static void file_read_action( Line 810  static void file_read_action(
                                 "read failed: actually read %u bytes count not in [0..%u] valid range",                                   "read failed: actually read %u bytes count not in [0..%u] valid range", 
                                         *info.data_size, to_read_size);                                           *info.data_size, to_read_size); 
         } else { // empty file          } else { // empty file
                 if(as_text) {                  // for both, text and binary: for text we need that terminator, for binary we need nonzero pointer to be able to save such files
                         *info.data=new(PointerFreeGC) char[1];                   *info.data=new(PointerFreeGC) char[1]; 
                         *(char*)(*info.data)=0;                  *(char*)(*info.data)=0;
                 } else   
                         *info.data=0;  
                 *info.data_size=0;                  *info.data_size=0;
                 return;                  return;
         }          }
Line 733  File_read_result file_read(Request_chars Line 824  File_read_result file_read(Request_chars
         File_read_result result={false, 0, 0, 0};          File_read_result result={false, 0, 0, 0};
 #ifdef PA_HTTP  #ifdef PA_HTTP
         if(file_spec.starts_with("http://")) {          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                  // fail on read problem
                 File_read_http_result http=file_read_http(charsets, file_spec, as_text, params);                  File_read_http_result http=file_read_http(charsets, file_spec, as_text, params);
                 result.success=true;                  result.success=true;
Line 741  File_read_result file_read(Request_chars Line 837  File_read_result file_read(Request_chars
                 result.headers=http.headers;                   result.headers=http.headers; 
         } else {          } else {
 #endif  #endif
                 if(params && params->count())                  if(params) {
                         throw Exception("parser.runtime",                          int valid_options=get_valid_file_options_count(*params);
                                 0,                          if(valid_options!=params->count())
                                 "invalid option passed");                                  throw Exception("parser.runtime",
                                           0,
                                           "invalid option passed");
                   }
   
                 File_read_action_info info={&result.str, &result.length,                  File_read_action_info info={&result.str, &result.length,
                         buf, offset, count};                           buf, offset, count}; 

Removed from v.1.202  
changed lines
  Added in v.1.209


E-mail: