--- parser3/src/main/pa_common.C 2003/01/21 15:51:13 1.143 +++ parser3/src/main/pa_common.C 2003/09/01 12:27:27 1.153.2.1 @@ -5,14 +5,17 @@ Author: Alexandr Petrosian (http://paf.design.ru) */ -static const char* IDENT_COMMON_C="$Date: 2003/01/21 15:51:13 $"; +static const char* IDENT_COMMON_C="$Date: 2003/09/01 12:27:27 $"; #include "pa_common.h" #include "pa_exception.h" #include "pa_globals.h" #include "pa_hash.h" +#include "pa_table.h" #include "pa_vstring.h" #include "pa_vdate.h" +#include "pa_vhash.h" +#include "pa_vtable.h" #ifdef WIN32 # include @@ -171,10 +174,10 @@ static int http_read_response(String& re /* ********************** 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); @@ -182,33 +185,39 @@ static void timeout_handler(int sig){ #endif static int http_request(String& response, - const String *origin_string, - const char* host, int port, - const char* request, - int timeout, - bool fail_on_status_ne_200){ + const String *origin_string, + const char* host, int port, + const char* request, + int timeout, + bool fail_on_status_ne_200) { if(!host) throw Exception("http.host", origin_string, "zero hostname"); //never -#ifdef WE_CAN_USE_ALARM - signal(SIGALRM, timeout_handler); +#ifdef PA_USE_ALARM + signal(SIGALRM, timeout_handler); #endif int sock=-1; - try { - int result; -#ifdef WE_CAN_USE_ALARM - if(sigsetjmp(timeout_env, 1)) - throw Exception("http.timeout", - origin_string, - "timeout occured while retrieving document"); - else { - alarm(timeout); +#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"); + return 0; // never + } else { + alarm(timeout); #endif + try { + int result; struct sockaddr_in dest; - - if(!set_addr(&dest, host, port)) + + if(!set_addr(&dest, host, port)) throw Exception("http.host", origin_string, "can not resolve hostname \"%s\"", host); @@ -229,21 +238,26 @@ static int http_request(String& response result=http_read_response(response, sock, fail_on_status_ne_200); closesocket(sock); -#ifdef WE_CAN_USE_ALARM +#ifdef PA_USE_ALARM alarm(0); - } #endif - return result; - } catch(...) { - if(sock>=0) - closesocket(sock); -#ifdef WE_CAN_USE_ALARM - alarm(0); + return result; + } catch(...) { +#ifdef PA_USE_ALARM + alarm(0); #endif - /*re*/throw; + if(sock>=0) + closesocket(sock); + /*re*/throw; + } +#ifdef PA_USE_ALARM } +#endif } +#undef CRLF +#define CRLF "\r\n" + #ifndef DOXYGEN struct Http_pass_header_info { String* request; @@ -257,11 +271,12 @@ static void http_pass_header(const Hash: *(i.request)<(value), String::UL_HTTP_HEADER, false) - <<"\n"; + << CRLF; if(key.change_case(pool, String::CC_UPPER)=="USER-AGENT") i.user_agent_specified=true; } +/// @todo build .cookies field. use ^file.tables.SET-COOKIES.menu{ for now static void file_read_http(Pool& pool, const String& file_spec, void*& data, size_t& data_size, Hash *options=0, Hash** out_fields=0) { @@ -273,7 +288,7 @@ static void file_read_http(Pool& pool, c bool fail_on_status_ne_200=true; Value *vheaders=0; - String connect_string(pool); + String& connect_string=*new(pool) String(pool); // must not be local [exception may be reported outside] // not in ^sql{... UL_SQL ...} spirit, but closer to ^file::load one connect_string.append(file_spec, String::UL_URI); // tainted pieces -> URI pieces @@ -317,7 +332,7 @@ static void file_read_http(Pool& pool, c //making request String request(pool); - request<< method <<" "<< uri <<" HTTP/1.0\nHost: "<< host<<"\n"; + request<< method <<" "<< uri <<" HTTP/1.0" CRLF "Host: "<< host<< CRLF; bool user_agent_specified=false; if(vheaders && !vheaders->is_string()) { // allow empty if(Hash *headers=vheaders->get_hash(&connect_string)) { @@ -330,8 +345,8 @@ static void file_read_http(Pool& pool, c "headers param must be hash"); }; if(!user_agent_specified) // defaulting - request << "user-agent: " DEFAULT_USER_AGENT "\n"; - request<<"\n"; + request << "user-agent: " DEFAULT_USER_AGENT CRLF; + request<hash(0); + size_t pos_after_ref=0; - header_block.split(aheaders, &pos_after_ref, "\r\n", 2); + header_block.split(aheaders, &pos_after_ref, CRLF, 2); //processing headers for(int i=1;icstr()); - - headers.put( - line->mid(0, pos).change_case(pool, String::CC_UPPER), - new(pool) VString(line->mid(pos+2, line->size()))); + + const String& sname=line->mid(0, pos).change_case(pool, String::CC_UPPER); + const String& string=line->mid(pos+2, line->size()); + + // tables + { + Value *valready=(Value *)tables.get(sname); + bool existed=valready!=0; + Table *table; + if(existed) { + // second+ appearence + table=valready->get_table(); + } else { + // first appearence + Array& columns=*new(pool) Array(pool, 1); + columns+=new(pool) String(pool, "value"); + table=new(pool) Table(pool, 0, &columns); + } + // this string becomes next row + Array& row=*new(pool) Array(pool, 1); + row+=&string; + *table+=&row; + // not existed before? add it + if(!existed) + tables.put(sname, new(pool) VTable(pool, table)); + } + headers.put(sname, new(pool) VString(string)); } else throw Exception("http.response", &connect_string, @@ -444,6 +486,23 @@ bool file_read(Pool& pool, const String& return result; } +#ifdef PA_SAFE_MODE +void check_safe_mode(struct stat finfo, const String& file_spec, const char* fname) { + if(finfo.st_uid/*foreign?*/!=geteuid() + && finfo.st_gid/*foreign?*/!=getegid()) + throw Exception("parser.runtime", + &file_spec, + "parser is in safe mode: " + "reading files of foreign group and user disabled " + "[recompile parser with --disable-safe-mode configure option], " + "actual filename '%s', " + "fuid(%d)!=euid(%d) or fgid(%d)!=egid(%d)", + fname, + finfo.st_uid, geteuid(), + finfo.st_gid, getegid()); +} +#endif + bool file_read_action_under_lock(Pool& pool, const String& file_spec, const char* action_name, File_read_action action, void *context, bool as_text, @@ -476,12 +535,7 @@ bool file_read_action_under_lock(Pool& p strerror(errno), errno, fname); #ifdef PA_SAFE_MODE - if(finfo.st_uid/*foreign?*/!=geteuid() - && finfo.st_gid/*foreign?*/!=getegid()) - throw Exception("parser.runtime", - &file_spec, - "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); + check_safe_mode(finfo, file_spec, fname); #endif action(pool, finfo, f, file_spec, fname, as_text, context); @@ -777,7 +831,7 @@ size_t stdout_write(const void *buf, siz return size; #else - return fwrite(buf, 1, size, stdout); + return write(1/*handleof(stdout)*/, buf, size, stdout); #endif } @@ -955,6 +1009,7 @@ int pa_sleep(unsigned long secs, unsigne // attributed meaning +/// http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 static size_t date_attribute(const VDate& vdate, char *buf, size_t buf_size) { const char month_names[12][4]={ "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; @@ -967,7 +1022,7 @@ static size_t date_attribute(const VDate throw Exception(0, 0, "bad time in attribute value (seconds from epoch=%ld)", when); - return snprintf(buf, MAX_STRING, "%s, %.2d-%s-%.4d %.2d:%.2d:%.2d GMT", + return snprintf(buf, MAX_STRING, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT", days[tms->tm_wday], tms->tm_mday,month_names[tms->tm_mon],tms->tm_year+1900, tms->tm_hour,tms->tm_min,tms->tm_sec);