Diff for /parser3/src/main/pa_common.C between versions 1.183 and 1.199

version 1.183, 2004/04/05 13:37:06 version 1.199, 2004/12/10 07:55:22
Line 21  static const char * const IDENT_COMMON_C Line 21  static const char * const IDENT_COMMON_C
 #include "pa_vint.h"  #include "pa_vint.h"
 #include "pa_vhash.h"  #include "pa_vhash.h"
 #include "pa_vtable.h"  #include "pa_vtable.h"
   #include "pa_socks.h"
   
 #ifdef CYGWIN  #ifdef CYGWIN
 #define _GNU_H_WINDOWS32_SOCKETS  #define _GNU_H_WINDOWS32_SOCKETS
Line 142  static bool set_addr(struct sockaddr_in Line 143  static bool set_addr(struct sockaddr_in
     addr->sin_port=htons(port);       addr->sin_port=htons(port); 
     if(host) {      if(host) {
                 ulong packed_ip=inet_addr(host);                  ulong packed_ip=inet_addr(host);
                 struct hostent *hostIP = packed_ip==INADDR_NONE?                  if(packed_ip!=INADDR_NONE)
                         gethostbyname(host)                          memcpy(&addr->sin_addr, &packed_ip, sizeof(packed_ip)); 
                         : gethostbyaddr((char *)&packed_ip, sizeof(packed_ip), AF_INET);                  else {
                 if(hostIP)                           struct hostent *hostIP=gethostbyname(host);
                         memcpy(&addr->sin_addr, hostIP->h_addr, hostIP->h_length);                           if(hostIP) 
                 else                                  memcpy(&addr->sin_addr, hostIP->h_addr, hostIP->h_length); 
                         return false;                          else
                                   return false;
                   } 
     } else       } else 
                 addr->sin_addr.s_addr=INADDR_ANY;                  addr->sin_addr.s_addr=INADDR_ANY;
     return true;      return true;
Line 162  static int http_read_response(char*& res Line 165  static int http_read_response(char*& res
         while(true) {          while(true) {
                 char buf[MAX_STRING*10];                   char buf[MAX_STRING*10]; 
                 ssize_t received_size=recv(sock, buf, sizeof(buf), 0);                   ssize_t received_size=recv(sock, buf, sizeof(buf), 0); 
                 if(received_size<=0)                  if(received_size<=0) {
                           if(int no=pa_socks_errno())
                                   throw Exception("http.timeout", 
                                           0, 
                                           "error receiving response: %s (%d)", pa_socks_strerr(no), no); 
                         break;                          break;
                   }
                 response=(char*)pa_realloc(response, response_size+received_size+1/*terminator*/);                  response=(char*)pa_realloc(response, response_size+received_size+1/*terminator*/);
                 memcpy(response+response_size, buf, received_size);                  memcpy(response+response_size, buf, received_size);
                 response_size+=received_size;                  response_size+=received_size;
                 response[response_size]=0;                  response[response_size]=0;
   
                 if(!result && (EOLat=strstr(response, CRLF))) { // checking status in first response                  if(!result && (EOLat=strstr(response, "\n"))) { // checking status in first response
                         const String status_line(pa_strdup(response, EOLat-response));                          const String status_line(pa_strdup(response, EOLat-response));
                         ArrayString astatus;                           ArrayString astatus; 
                         size_t pos_after=0;                          size_t pos_after=0;
Line 199  static int http_read_response(char*& res Line 207  static int http_read_response(char*& res
   
 #ifdef PA_USE_ALARM  #ifdef PA_USE_ALARM
 static sigjmp_buf timeout_env;  static sigjmp_buf timeout_env;
 static void timeout_handler(int sig){  static void timeout_handler(int /*sig*/){
     siglongjmp(timeout_env, 1);       siglongjmp(timeout_env, 1); 
 }  }
 #endif  #endif
   
 static int http_request(char*& response, size_t& response_size,  static int http_request(char*& response, size_t& response_size,
                         const char* host, int port,                           const char* host, short port, 
                         const char* request,                           const char* request, 
                         int                           int timeout_secs,
 #ifdef PA_USE_ALARM  
                         timeout  
 #endif  
                         ,  
                         bool fail_on_status_ne_200) {                          bool fail_on_status_ne_200) {
         if(!host)          if(!host)
                 throw Exception("http.host",                   throw Exception("http.host", 
                         0,                           0, 
                         "zero hostname");  //never                          "zero hostname");  //never
   
           volatile int sock=-1;
 #ifdef PA_USE_ALARM  #ifdef PA_USE_ALARM
         signal(SIGALRM, timeout_handler);           signal(SIGALRM, timeout_handler); 
 #endif  #endif
         int sock=-1;  
 #ifdef PA_USE_ALARM  #ifdef PA_USE_ALARM
         if(sigsetjmp(timeout_env, 1)) {          if(sigsetjmp(timeout_env, 1)) {
                 // stupid gcc [2.95.4] generated bad code                  // stupid gcc [2.95.4] generated bad code
                 // which failed to handle sigsetjmp+throw: crashed inside of pre-throw code.                  // which failed to handle sigsetjmp+throw: crashed inside of pre-throw code.
                 // rewritten simplier [though duplicating closesocket code]                  // rewritten simplier [athough duplicating closesocket code]
                 if(sock>=0)                   if(sock>=0) 
                         closesocket(sock);                           closesocket(sock); 
                 throw Exception("http.timeout",                   throw Exception("http.timeout", 
                         origin_string,                           0, 
                         "timeout occured while retrieving document");                           "timeout occured while retrieving document"); 
                 return 0; // never                  return 0; // never
         } else {          } else {
                 alarm(timeout);                   alarm(timeout_secs); 
 #endif  #endif
                 try {                  try {
                         int result;                          int result;
Line 245  static int http_request(char*& response, Line 249  static int http_request(char*& response,
                                         0,                                           0, 
                                         "can not resolve hostname \"%s\"", host);                                           "can not resolve hostname \"%s\"", host); 
                                                   
                         if((sock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP/*0*/))<0)                          if((sock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP/*0*/))<0) {
                                   int no=pa_socks_errno();
                                 throw Exception("http.connect",                                   throw Exception("http.connect", 
                                         0,                                           0, 
                                         "can not make socket: %s (%d)", strerror(errno), errno);                                           "can not make socket: %s (%d)", pa_socks_strerr(no), no); 
                         if(connect(sock, (struct sockaddr *)&dest, sizeof(dest)))                          }
   
   #ifdef SO_DONTLINGER
                           int dont_linger = 0;
                           setsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (const char *)&dont_linger, sizeof(dont_linger));
   #else
                           // To enable SO_DONTLINGER (that is, disable SO_LINGER) 
                           // l_onoff should be set to zero and setsockopt should be called
                           linger dont_linger={0,0};
                           setsockopt(sock, SOL_SOCKET, SO_LINGER, (const char *)&dont_linger, sizeof(dont_linger));
   #endif
   
   #if defined(SO_SNDTIMEO) || defined(SO_RCVTIMEO)
                           int timeout_ms=timeout_secs*1000;
   #endif
   #ifdef SO_SNDTIMEO
                           setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout_ms, sizeof(timeout_ms));
   #endif
   #ifdef SO_RCVTIMEO
                           setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout_ms, sizeof(timeout_ms));
   #endif
   
                           if(connect(sock, (struct sockaddr *)&dest, sizeof(dest))) {
                                   int no=pa_socks_errno();
                                 throw Exception("http.connect",                                   throw Exception("http.connect", 
                                         0,                                           0, 
                                         "can not connect to host \"%s\": %s (%d)", host, strerror(errno), errno);                                           "can not connect to host \"%s\": %s (%d)", host, pa_socks_strerr(no), no); 
                           }
                         size_t request_size=strlen(request);                          size_t request_size=strlen(request);
                         if(send(sock, request, request_size, 0)!=(ssize_t)request_size)                          if(send(sock, request, request_size, 0)!=(ssize_t)request_size) {
                                 throw Exception("http.connect",                                   int no=pa_socks_errno();
                                   throw Exception("http.timeout", 
                                         0,                                           0, 
                                         "error sending request: %s (%d)", strerror(errno), errno);                                           "error sending request: %s (%d)", pa_socks_strerr(no), no); 
                           }
   
                         result=http_read_response(response, response_size, sock, fail_on_status_ne_200);                           result=http_read_response(response, response_size, sock, fail_on_status_ne_200); 
                         closesocket(sock);                           closesocket(sock); 
Line 391  struct File_read_http_result { Line 422  struct File_read_http_result {
         HashStringValue* headers;          HashStringValue* headers;
 };   }; 
 #endif  #endif
   static void find_headers_end(char* p,
                   char*& headers_end_at,
                   char*& raw_body)
   {
           raw_body=p;
           // \n\n
           // \r\n\r\n
           while((p=strchr(p, '\n'))) {
                   headers_end_at=++p; // \n>.<
                   if(*p=='\r')  // \r\n>\r?<\n
                           p++;
                   if(*p=='\n') { // \r\n\r>\n?<
                           raw_body=p+1;
                           return;                 
                   }
           }
           headers_end_at=0;
   }
   
 /// @todo build .cookies field. use ^file.tables.SET-COOKIES.menu{ for now  /// @todo build .cookies field. use ^file.tables.SET-COOKIES.menu{ for now
 static File_read_http_result file_read_http(Request_charsets& charsets,   static File_read_http_result file_read_http(Request_charsets& charsets, 
                                             const String& file_spec,                                               const String& file_spec, 
Line 399  static File_read_http_result file_read_h Line 449  static File_read_http_result file_read_h
         File_read_http_result result;          File_read_http_result result;
         char host[MAX_STRING];           char host[MAX_STRING]; 
         const char* uri;           const char* uri; 
         int port;          short port;
         const char* method="GET"; bool method_is_get;          const char* method="GET"; bool method_is_get;
         HashStringValue* form=0;          HashStringValue* form=0;
         const char* body_cstr=0;          const char* body_cstr=0;
         int timeout=2;          int timeout_secs=2;
         bool fail_on_status_ne_200=true;          bool fail_on_status_ne_200=true;
         Value* vheaders=0;          Value* vheaders=0;
         Charset *asked_remote_charset=0;          Charset *asked_remote_charset=0;
Line 426  static File_read_http_result file_read_h Line 476  static File_read_http_result file_read_h
                 }                   } 
                 if(Value* vtimeout=options->get(HTTP_TIMEOUT_NAME)) {                  if(Value* vtimeout=options->get(HTTP_TIMEOUT_NAME)) {
                         valid_options++;                          valid_options++;
                         timeout=vtimeout->as_int();                           timeout_secs=vtimeout->as_int(); 
                 }                   } 
                 if((vheaders=options->get(HTTP_HEADERS_NAME))) {                  if((vheaders=options->get(HTTP_HEADERS_NAME))) {
                         valid_options++;                          valid_options++;
Line 487  static File_read_http_result file_read_h Line 537  static File_read_http_result file_read_h
                 uri=host_uri?current+(host_uri-1-host):"/";                   uri=host_uri?current+(host_uri-1-host):"/"; 
                 char* port_cstr=lsplit(host, ':');                   char* port_cstr=lsplit(host, ':'); 
                 char* error_pos=0;                  char* error_pos=0;
                 port=port_cstr?strtol(port_cstr, &error_pos, 0):80;                  port=port_cstr?(short)strtol(port_cstr, &error_pos, 0):80;
   
                 if(strchr(uri, '?') && form)                  if(strchr(uri, '?') && form)
                         throw Exception("parser.runtime",                          throw Exception("parser.runtime",
Line 558  static File_read_http_result file_read_h Line 608  static File_read_http_result file_read_h
         size_t response_size;          size_t response_size;
         int status_code=http_request(response, response_size,          int status_code=http_request(response, response_size,
                 host, port, request_head_and_body.cstr(),                   host, port, request_head_and_body.cstr(), 
                 timeout, fail_on_status_ne_200);                   timeout_secs, fail_on_status_ne_200); 
                   
         //processing results              //processing results    
         char* raw_body; size_t raw_body_size;          char* raw_body; size_t raw_body_size;
         char* headers_end_at=strstr(response, CRLF CRLF /*change '4' below along!*/);           char* headers_end_at;
         if(headers_end_at) {          find_headers_end(response, 
                 raw_body=headers_end_at+4;                  headers_end_at,
                 raw_body_size=response_size-(raw_body-response);                  raw_body);
         } else          raw_body_size=response_size-(raw_body-response);
                 throw Exception("http.response",   
                         &connect_string,  
                         "bad response from host - no headers found");   
           
         *headers_end_at=0;  
         const String header_block(response, headers_end_at-response, true);  
                   
         ArrayString aheaders;  
         result.headers=new HashStringValue;          result.headers=new HashStringValue;
         VHash* vtables=new VHash;          VHash* vtables=new VHash;
         result.headers->put(HTTP_TABLES_NAME, vtables);          result.headers->put(HTTP_TABLES_NAME, vtables);
         HashStringValue& tables=vtables->hash();  
   
         size_t pos_after=0;  
         header_block.split(aheaders, pos_after, CRLF);   
           
         //processing headers  
         size_t aheaders_count=aheaders.count();  
         Charset* real_remote_charset=0; // undetected, yet          Charset* real_remote_charset=0; // undetected, yet
         for(size_t i=1; i<aheaders_count; i++) {  
                 const String& line=*aheaders.get(i);          if(headers_end_at) {
                 size_t pos=line.pos(": ", 2);                   *headers_end_at=0;
                 if(pos==STRING_NOT_FOUND || pos<1)                  const String header_block(String::C(response, headers_end_at-response), true);
                         throw Exception("http.response",                   
                                 &connect_string,                  ArrayString aheaders;
                                 "bad response from host - bad header \"%s\"", line.cstr());                  HashStringValue& tables=vtables->hash();
                 const String::Body HEADER_NAME=  
                         line.mid(0, pos).change_case(charsets.source(), String::CC_UPPER);                  size_t pos_after=0;
                 const String& header_value=line.mid(pos+2, line.length());                  header_block.split(aheaders, pos_after, "\n"); 
                 if(HEADER_NAME=="CONTENT-TYPE")                  
                         real_remote_charset=detect_charset(charsets.source(), header_value);                  //processing headers
                   size_t aheaders_count=aheaders.count();
                 // tables                  for(size_t i=1; i<aheaders_count; i++) {
                 {                          const String& line=*aheaders.get(i);
                         Value *valready=(Value *)tables.get(HEADER_NAME);                          size_t pos=line.pos(':'); 
                         bool existed=valready!=0;                          if(pos==STRING_NOT_FOUND || pos<1)
                         Table *table;                                  throw Exception("http.response", 
                         if(existed) {                                          &connect_string,
                                 // second+ appearence                                          "bad response from host - bad header \"%s\"", line.cstr());
                                 table=valready->get_table();                          const String::Body HEADER_NAME=
                         } else {                                  line.mid(0, pos).change_case(charsets.source(), String::CC_UPPER);
                                 // first appearence                          const String& header_value=line.mid(pos+1, line.length()).trim(String::TRIM_BOTH, " \t\r");
                                 Table::columns_type columns =new ArrayString(1);                          if(as_text && HEADER_NAME=="CONTENT-TYPE")
                                 *columns+=new String("value");                                  real_remote_charset=detect_charset(charsets.source(), header_value);
                                 table=new Table(columns);  
                           // tables
                           {
                                   Value *valready=(Value *)tables.get(HEADER_NAME);
                                   bool existed=valready!=0;
                                   Table *table;
                                   if(existed) {
                                           // second+ appearence
                                           table=valready->get_table();
                                   } else {
                                           // first appearence
                                           Table::columns_type columns =new ArrayString(1);
                                           *columns+=new String("value");
                                           table=new Table(columns);
                                   }
                                   // this string becomes next row
                                   ArrayString& row=*new ArrayString(1);
                                   row+=&header_value;
                                   *table+=&row;
                                   // not existed before? add it
                                   if(!existed)
                                           tables.put(HEADER_NAME, new VTable(table));
                         }                          }
                         // this string becomes next row  
                         ArrayString& row=*new ArrayString(1);  
                         row+=&header_value;  
                         *table+=&row;  
                         // not existed before? add it  
                         if(!existed)  
                                 tables.put(HEADER_NAME, new VTable(table));  
                 }  
   
                 result.headers->put(HEADER_NAME, new VString(header_value));                          result.headers->put(HEADER_NAME, new VString(header_value));
                   }
         }          }
         // defaulting to used-asked charset [it's never empty!]  
         if(!real_remote_charset)  
                 real_remote_charset=asked_remote_charset;  
   
         // output response          // output response
         String::C real_body=String::C(raw_body, raw_body_size);          String::C real_body=String::C(raw_body, raw_body_size);
         if(as_text && raw_body_size) // must be checked because transcode returns CONST string in case length==0, which contradicts hacking few lines below          if(as_text && raw_body_size) { // must be checked because transcode returns CONST string in case length==0, which contradicts hacking few lines below
                   // defaulting to used-asked charset [it's never empty!]
                   if(!real_remote_charset)
                           real_remote_charset=asked_remote_charset;
                 real_body=Charset::transcode(real_body, *real_remote_charset, charsets.source());                  real_body=Charset::transcode(real_body, *real_remote_charset, charsets.source());
           }
   
         result.str=const_cast<char *>(real_body.str); // hacking a little          result.str=const_cast<char *>(real_body.str); // hacking a little
         result.length=real_body.length;          result.length=real_body.length;
Line 644  static File_read_http_result file_read_h Line 695  static File_read_http_result file_read_h
 #ifndef DOXYGEN  #ifndef DOXYGEN
 struct File_read_action_info {  struct File_read_action_info {
         char **data; size_t *data_size;          char **data; size_t *data_size;
           char* buf; size_t offset; size_t count;
 };   }; 
 #endif  #endif
 static void file_read_action(  static void file_read_action(
Line 652  static void file_read_action( Line 704  static void file_read_action(
                              const String& file_spec, const char* /*fname*/, bool as_text,                                const String& file_spec, const char* /*fname*/, bool as_text, 
                              void *context) {                               void *context) {
         File_read_action_info& info=*static_cast<File_read_action_info *>(context);           File_read_action_info& info=*static_cast<File_read_action_info *>(context); 
         if(size_t to_read_size=(size_t)finfo.st_size) {           size_t to_read_size=info.count;
                 *info.data=new(PointerFreeGC) char[to_read_size+(as_text?1:0)];           if(!to_read_size)
                   to_read_size=(size_t)finfo.st_size;
           assert( !(info.buf && as_text) );
           if(to_read_size) { 
                   if(info.offset)
                           lseek(f, info.offset, SEEK_SET);
                   *info.data=info.buf
                           ? info.buf
                           : new(PointerFreeGC) char[to_read_size+(as_text?1:0)]; 
                 *info.data_size=(size_t)read(f, *info.data, to_read_size);                   *info.data_size=(size_t)read(f, *info.data, to_read_size); 
   
                 if(ssize_t(*info.data_size)<0 || *info.data_size>to_read_size)                  if(ssize_t(*info.data_size)<0 || *info.data_size>to_read_size)
Line 673  static void file_read_action( Line 733  static void file_read_action(
 }  }
 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) {
         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://")) {
Line 690  File_read_result file_read(Request_chars Line 751  File_read_result file_read(Request_chars
                                 0,                                  0,
                                 "invalid option passed");                                  "invalid option passed");
   
                 File_read_action_info info={&result.str, &result.length};                   File_read_action_info info={&result.str, &result.length,
                           buf, offset, count}; 
                 result.success=file_read_action_under_lock(file_spec,                   result.success=file_read_action_under_lock(file_spec, 
                         "read", file_read_action, &info,                           "read", file_read_action, &info, 
                         as_text, fail_on_read_problem);                           as_text, fail_on_read_problem); 
Line 1045  const char* format(double value, char* f Line 1107  const char* format(double value, char* f
   
 size_t stdout_write(const void *buf, size_t size) {  size_t stdout_write(const void *buf, size_t size) {
 #ifdef WIN32  #ifdef WIN32
           size_t to_write = size;
         do{          do{
                 int chunk_written=fwrite(buf, 1, min((size_t)8*0x400, size), stdout);                   int chunk_written=fwrite(buf, 1, min((size_t)8*0x400, size), stdout); 
                 if(chunk_written<=0)                  if(chunk_written<=0)
Line 1053  size_t stdout_write(const void *buf, siz Line 1116  size_t stdout_write(const void *buf, siz
                 buf=((const char*)buf)+chunk_written;                  buf=((const char*)buf)+chunk_written;
         } while(size>0);           } while(size>0); 
   
         return size;          return to_write-size;
 #else  #else
         return fwrite(buf, 1, size, stdout);           return fwrite(buf, 1, size, stdout); 
 #endif  #endif
Line 1066  char* unescape_chars(const char* cp, int Line 1129  char* unescape_chars(const char* cp, int
                 EscapeFirst,                   EscapeFirst, 
                 EscapeSecond                  EscapeSecond
         } escapeState=EscapeRest;          } escapeState=EscapeRest;
         int escapedValue=0;          uchar escapedValue=0;
         int srcPos=0;          int srcPos=0;
         int dstPos=0;          int dstPos=0;
         while(srcPos < len) {          while(srcPos < len) {
                 int ch=cp[srcPos];                   uchar ch=(uchar)cp[srcPos]; 
                 switch(escapeState) {                  switch(escapeState) {
                         case EscapeRest:                          case EscapeRest:
                         if(ch=='%') {                          if(ch=='%') {
Line 1082  char* unescape_chars(const char* cp, int Line 1145  char* unescape_chars(const char* cp, int
                         }                          }
                         break;                          break;
                         case EscapeFirst:                          case EscapeFirst:
                         escapedValue=hex_value[ch] << 4;                                  escapedValue=(uchar)(hex_value[ch] << 4);
                         escapeState=EscapeSecond;                          escapeState=EscapeSecond;
                         break;                          break;
                         case EscapeSecond:                          case EscapeSecond:
Line 1123  bool StrEqNc(const char* s1, const char* Line 1186  bool StrEqNc(const char* s1, const char*
                                 return !strict;                                  return !strict;
                 } else if(!(*s2))                  } else if(!(*s2))
                         return !strict;                          return !strict;
                 if(isalpha(*s1)) {                  if(isalpha((unsigned char)*s1)) {
                         if(tolower(*s1) !=tolower(*s2))                          if(tolower((unsigned char)*s1) !=tolower((unsigned char)*s2))
                                 return false;                                  return false;
                 } else if((*s1) !=(*s2))                  } else if((*s1) !=(*s2))
                         return false;                          return false;
Line 1264  static char *base64_alphabet = Line 1327  static char *base64_alphabet =
 static size_t  static size_t
 g_mime_utils_base64_encode_step (const unsigned char *in, size_t inlen, unsigned char *out, int *state, int *save)  g_mime_utils_base64_encode_step (const unsigned char *in, size_t inlen, unsigned char *out, int *state, int *save)
 {  {
         const register unsigned char *inptr;          register const unsigned char *inptr;
         register unsigned char *outptr;          register unsigned char *outptr;
                   
         if (inlen <= 0)          if (inlen <= 0)

Removed from v.1.183  
changed lines
  Added in v.1.199


E-mail: