--- parser3/src/main/pa_common.C 2002/11/29 08:06:59 1.135 +++ parser3/src/main/pa_common.C 2003/02/24 12:38:54 1.140.2.1 @@ -5,7 +5,7 @@ Author: Alexandr Petrosian (http://paf.design.ru) */ -static const char* IDENT_COMMON_C="$Date: 2002/11/29 08:06:59 $"; +static const char* IDENT_COMMON_C="$Date: 2003/02/24 12:38:54 $"; #include "pa_common.h" #include "pa_exception.h" @@ -29,6 +29,16 @@ static const char* IDENT_COMMON_C="$Date # define _O_BINARY 0 #endif +#ifdef HAVE_FTRUNCATE +# define PA_O_TRUNC 0 +#else +# ifdef _O_TRUNC +# define PA_O_TRUNC _O_TRUNC +# else +# error you must have either ftruncate function or _O_TRUNC bit declared +# endif +#endif + // locking constants #ifdef HAVE_FLOCK @@ -77,28 +87,17 @@ static int unlock(int fd) { FLOCK(F_TLOC #define DEFAULT_USER_AGENT "parser3" - -static char* strnchr(char* buf, size_t size, char c) { - // sanity check - if(!buf) - return 0; - - for(; size-->0; buf++) { - if(*buf==c) - return buf; - } - - return 0; -} - void fix_line_breaks(char* buf, size_t& size) { + if(size==0) + return; + //_asm int 3; const char* const eob=buf+size; char* dest=buf; // fix DOS: \r\n -> \n // fix Macintosh: \r -> \n char* bol=buf; - while(char* eol=strnchr(bol, eob -bol, '\r')) { + while(char* eol=(char*)memchr(bol, '\r', eob -bol)) { size_t len=eol-bol; if(dest!=bol) memcpy(dest, bol, len); @@ -172,10 +171,10 @@ static void http_read_response(String& r /* ********************** request *************************** */ #if defined(SIGALRM) && defined(HAVE_SIGSETJMP) && defined(HAVE_SIGLONGJMP) -# define WE_CAN_USE_ALARM +# define PA_USE_ALARM #endif -#ifdef WE_CAN_USE_ALARM +#ifdef PA_USE_ALARM static sigjmp_buf timeout_env; static void timeout_handler(int sig){ siglongjmp(timeout_env, 1); @@ -192,50 +191,54 @@ static void http_request(String& respons origin_string, "zero hostname"); //never -#ifdef WE_CAN_USE_ALARM +#ifdef PA_USE_ALARM signal(SIGALRM, timeout_handler); #endif int sock=-1; +#ifdef PA_USE_ALARM + if(sigsetjmp(timeout_env, 1)) { + // stupid gcc [2.95.4] generated bad code + // which failed to handle sigsetjmp+throw: crashed inside of pre-throw code. + // rewritten simplier [though duplicating closesocket code] + if(sock>=0) + closesocket(sock); + throw Exception("http.timeout", + origin_string, + "timeout occured while retrieving document"); + } else { + alarm(timeout); +#endif try { -#ifdef WE_CAN_USE_ALARM - if(sigsetjmp(timeout_env, 1)) - throw Exception("http.timeout", + struct sockaddr_in dest; + + if(!set_addr(&dest, host, port)) + throw Exception("http.host", origin_string, - "timeout occured while retrieving document"); - else { - alarm(timeout); -#endif - struct sockaddr_in dest; + "can not resolve hostname \"%s\"", host); - if(!set_addr(&dest, host, port)) - throw Exception("http.host", - origin_string, - "can not resolve hostname \"%s\"", host); - - if((sock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP/*0*/))<0) - throw Exception("http.connect", - origin_string, - "can not make socket: %s (%d)", strerror(errno), errno); - if(connect(sock, (struct sockaddr *)&dest, sizeof(dest))) - throw Exception("http.connect", - origin_string, - "can not connect to host \"%s\": %s (%d)", host, strerror(errno), errno); - size_t request_size=strlen(request); - if(send(sock, request, request_size, 0)!=(ssize_t)request_size) - throw Exception("http.connect", - origin_string, - "error sending request: %s (%d)", strerror(errno), errno); - - http_read_response(response, sock); - if(sock>=0) - closesocket(sock); -#ifdef WE_CAN_USE_ALARM - } + if((sock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP/*0*/))<0) + throw Exception("http.connect", + origin_string, + "can not make socket: %s (%d)", strerror(errno), errno); + if(connect(sock, (struct sockaddr *)&dest, sizeof(dest))) + throw Exception("http.connect", + origin_string, + "can not connect to host \"%s\": %s (%d)", host, strerror(errno), errno); + size_t request_size=strlen(request); + if(send(sock, request, request_size, 0)!=(ssize_t)request_size) + throw Exception("http.connect", + origin_string, + "error sending request: %s (%d)", strerror(errno), errno); + + http_read_response(response, sock); + closesocket(sock); +#ifdef PA_USE_ALARM + alarm(0); #endif } catch(...) { if(sock>=0) closesocket(sock); -#ifdef WE_CAN_USE_ALARM +#ifdef PA_USE_ALARM alarm(0); #endif /*re*/throw; @@ -254,7 +257,7 @@ static void http_pass_header(const Hash: Pool& pool=i.request->pool(); *(i.request)<(value), String::UL_URI) + << attributed_meaning_to_string(*static_cast(value), String::UL_HTTP_HEADER, false) <<"\n"; if(key.change_case(pool, String::CC_UPPER)=="USER-AGENT") @@ -471,11 +474,12 @@ bool file_read_action_under_lock(Pool& p "stat failed: %s (%d), actual filename '%s'", strerror(errno), errno, fname); -#ifdef NO_FOREIGN_GROUP_FILES - if(finfo.st_gid/*foreign?*/!=getegid()) +#ifdef PA_SAFE_MODE + if(finfo.st_uid/*foreign?*/!=geteuid() + && finfo.st_gid/*foreign?*/!=getegid()) throw Exception("parser.runtime", &file_spec, - "parser reading files of foreign group disabled [recompile parser without --disable-foreign-group-files configure option], actual filename '%s'", + "parser is in safe mode: reading files of foreign group and user disabled [recompile parser with --disable-safe-mode configure option], actual filename '%s'", fname); #endif @@ -523,7 +527,7 @@ bool file_write_action_under_lock( if((f=open(fname, O_CREAT|O_RDWR |(as_text?_O_TEXT:_O_BINARY) - |(do_append?O_APPEND:0), 0664))>=0) { + |(do_append?O_APPEND:PA_O_TRUNC), 0664))>=0) { if((do_block?lock_exclusive_blocking(f):lock_exclusive_nonblocking(f))!=0) { Exception e("file.lock", &file_spec, @@ -538,14 +542,18 @@ bool file_write_action_under_lock( try { action(f, context); } catch(...) { +#ifdef HAVE_FTRUNCATE if(!do_append) ftruncate(f, lseek(f, 0, SEEK_CUR)); // one can not use O_TRUNC, read lower +#endif unlock(f);close(f); /*re*/throw; } +#ifdef HAVE_FTRUNCATE if(!do_append) ftruncate(f, lseek(f, 0, SEEK_CUR)); // O_TRUNC truncates even exclusevely write-locked file [thanks to Igor Milyakov for discovering] +#endif unlock(f);close(f); return true; } else @@ -964,9 +972,9 @@ static size_t date_attribute(const VDate tms->tm_hour,tms->tm_min,tms->tm_sec); } static void append_attribute_meaning(String& result, - Value& value, String::Untaint_lang lang) { + Value& value, String::Untaint_lang lang, bool forced) { if(const String *string=value.get_string()) - result.append(string->join_chains(result.pool(), 0), lang, true); + result.append(string->join_chains(result.pool(), 0), lang, forced); else if(Value *vdate=value.as(VDATE_TYPE, false)) { char *buf=(char *)result.malloc(MAX_STRING); @@ -984,6 +992,7 @@ static void append_attribute_meaning(Str struct Attributed_meaning_info { String *header; // header line being constructed String::Untaint_lang lang; // language in which to append to that line + bool forced; // do they force that lang? }; #endif static void append_attribute_subattribute(const Hash::Key& akey, Hash::Val *avalue, @@ -995,22 +1004,22 @@ static void append_attribute_subattribut // ...; charset=windows1251 *ami.header << "; "; - ami.header->append(akey, ami.lang, true); + ami.header->append(akey, ami.lang, ami.forced); *ami.header << "="; - append_attribute_meaning(*ami.header, *static_cast(avalue), ami.lang); + append_attribute_meaning(*ami.header, *static_cast(avalue), ami.lang, ami.forced); } const String& attributed_meaning_to_string(Value& meaning, - String::Untaint_lang lang) { + String::Untaint_lang lang, bool forced) { String &result=*new(meaning.pool()) String(meaning.pool()); if(Hash *hash=meaning.get_hash(0)) { // $value(value) $subattribute(subattribute value) if(Value *value=static_cast(hash->get(*value_name))) - append_attribute_meaning(result, *value, lang); + append_attribute_meaning(result, *value, lang, forced); Attributed_meaning_info attributed_meaning_info={&result, lang}; hash->for_each(append_attribute_subattribute, &attributed_meaning_info); } else // result value - append_attribute_meaning(result, meaning, lang); + append_attribute_meaning(result, meaning, lang, forced); return result; }