|
|
| version 1.143.2.15, 2003/02/04 15:59:05 | version 1.143.2.21.2.3, 2003/03/19 16:28:08 |
|---|---|
| Line 93 static int unlock(int fd) { FLOCK(F_TLOC | Line 93 static int unlock(int fd) { FLOCK(F_TLOC |
| #endif | #endif |
| #endif | #endif |
| // defines for globals | |
| #define FILE_STATUS_NAME "status" | |
| // globals | |
| const String& file_status_name(new String(FILE_STATUS_NAME)); | |
| // defines for statics | // defines for statics |
| #define HTTP_METHOD_NAME "method" | #define HTTP_METHOD_NAME "method" |
| #define HTTP_TIMEOUT_NAME "timeout" | #define HTTP_TIMEOUT_NAME "timeout" |
| #define HTTP_HEADERS_NAME "headers" | #define HTTP_HEADERS_NAME "headers" |
| #define HTTP_ANY_STATUS_NAME "any-status" | #define HTTP_ANY_STATUS_NAME "any-status" |
| #define FILE_STATUS_NAME "status" | |
| // statics | // statics |
| static StringPtr http_method_name(new String(HTTP_METHOD_NAME)); | static const String& http_method_name(new String(HTTP_METHOD_NAME)); |
| static StringPtr http_timeout_name(new String(HTTP_TIMEOUT_NAME)); | static const String& http_timeout_name(new String(HTTP_TIMEOUT_NAME)); |
| static StringPtr http_headers_name(new String(HTTP_HEADERS_NAME)); | static const String& http_headers_name(new String(HTTP_HEADERS_NAME)); |
| static StringPtr http_any_status_name(new String(HTTP_ANY_STATUS_NAME)); | static const String& http_any_status_name(new String(HTTP_ANY_STATUS_NAME)); |
| static StringPtr file_status_name(new String(FILE_STATUS_NAME)); | |
| // defines | // defines |
| Line 143 void fix_line_breaks(char* buf, size_t& | Line 149 void fix_line_breaks(char* buf, size_t& |
| memcpy(dest, bol, eob-bol); | memcpy(dest, bol, eob-bol); |
| } | } |
| char* file_read_text(Pool& pool, Charset& charset, | char* file_read_textCharset& charset, |
| StringPtr file_spec, | const String& file_spec, |
| bool fail_on_read_problem, | bool fail_on_read_problem, |
| HashStringValue *params, HashStringValue** out_fields) { | HashStringValue* params/*, HashStringValue* * out_fields*/) { |
| char *result; size_t size; | File_read_result file= |
| File_read_result file_read_result=file_read(pool, charset, file_spec, result, size, true, params, out_fields, fail_on_read_problem); | file_read(pool, charset, file_spec, true, params, fail_on_read_problem); |
| return file_read_result.success?result:0; | return file.success?file.data:0; |
| } | } |
| //http request stuff | //http request stuff |
| Line 169 static bool set_addr(struct sockaddr_in | Line 175 static bool set_addr(struct sockaddr_in |
| return true; | return true; |
| } | } |
| static int http_read_response(Pool& pool, String& response, int sock, bool fail_on_status_ne_200){ | static int http_read_responseString& response, int sock, bool fail_on_status_ne_200){ |
| int result=0; | int result=0; |
| ssize_t EOLat=0; | ssize_t EOLat=0; |
| while(true) { | while(true) { |
| char *buf=(char *)pool.malloc(MAX_STRING); | char *buf=new char[MAX_STRING]; |
| ssize_t size=recv(sock, buf, MAX_STRING, 0); | ssize_t size=recv(sock, buf, MAX_STRING, 0); |
| if(size<=0) | if(size<=0) |
| break; | break; |
| response.APPEND_TAINTED(buf, size, "remote HTTP server response", 0); | response.APPEND_TAINTED(buf, size, "remote HTTP server response", 0); |
| if(!result && (EOLat=response.pos("\r\n", 2))>=0) { // checking status in first response | if(!result && (EOLat=response.pos("\r\n", 2))>=0) { // checking status in first response |
| StringPtr status_line=response.mid(0, (size_t)EOLat); | const String& status_line=response.mid(0, (size_t)EOLat); |
| ArrayString astatus; | ArrayString astatus; |
| status_line->split(astatus, 0, " ", 1); | status_line->split(astatus, 0, " ", 1); |
| StringPtr status_code=astatus.get(1); | const String& status_code=astatus.get(1); |
| result=status_code->as_int(); | result=status_code->as_int(); |
| if(fail_on_status_ne_200 && result!=200) | if(fail_on_status_ne_200 && result!=200) |
| Line 195 static int http_read_response(Pool& pool | Line 201 static int http_read_response(Pool& pool |
| return result; | return result; |
| else | else |
| throw Exception("http.response", | throw Exception("http.response", |
| Exception::undefined_source, | 0, |
| "bad response from host - no status found (size=%lu)", response.size()); | "bad response from host - no status found (size=%lu)", response.size()); |
| } | } |
| Line 212 static void timeout_handler(int sig){ | Line 218 static void timeout_handler(int sig){ |
| } | } |
| #endif | #endif |
| static int http_request(Pool& pool, | static int http_request( |
| String& response, | String& response, |
| StringPtr origin_string, | const String* origin_string, |
| const char* host, int port, | const char* host, int port, |
| const char* request, | const char* request, |
| int timeout, | int timeout, |
| Line 278 static int http_request(Pool& pool, | Line 284 static int http_request(Pool& pool, |
| #ifndef DOXYGEN | #ifndef DOXYGEN |
| struct Http_pass_header_info { | struct Http_pass_header_info { |
| Pool* pool; | ; |
| Charset* charset; | Charset* charset; |
| String* request; | String* request; |
| bool user_agent_specified; | bool user_agent_specified; |
| Line 293 static void http_pass_header(HashStringV | Line 299 static void http_pass_header(HashStringV |
| if(*key->change_case(*info->pool, *info->charset, String::CC_UPPER)=="USER-AGENT") | if(*key->change_case(*info->pool, *info->charset, String::CC_UPPER)=="USER-AGENT") |
| info->user_agent_specified=true; | info->user_agent_specified=true; |
| } | } |
| static HashStringValuePtr file_read_http(Pool& pool, Charset& charset, StringPtr file_spec, | #ifndef DOXYGEN |
| char*& data, size_t& data_size, | struct File_read_http_result { |
| HashStringValue *options=0, bool return_outfields=false) { | char *data; size_t size; |
| HashStringValuePtr result(0); | HashStringValue* headers; |
| }; | |
| #endif | |
| static File_read_http_result file_read_httpCharset& charset, const String& file_spec, | |
| HashStringValue *options=0) { | |
| File_read_http_result result; | |
| char host[MAX_STRING]; | char host[MAX_STRING]; |
| const char* uri; | const char* uri; |
| int port; | int port; |
| CharPtr method(0); | const char* method(0); |
| int timeout=2; | int timeout=2; |
| bool fail_on_status_ne_200=true; | bool fail_on_status_ne_200=true; |
| ValuePtr vheaders(0); | ValuePtr vheaders(0); |
| StringPtr connect_string(new String()); | const String& connect_string(new String()); |
| // not in ^sql{... UL_SQL ...} spirit, but closer to ^file::load one | // not in ^sql{... UL_SQL ...} spirit, but closer to ^file::load one |
| connect_string->append(*file_spec, String::UL_URI); // tainted pieces -> URI pieces | connect_string->append(*file_spec, String::UL_URI); // tainted pieces -> URI pieces |
| CharPtr connect_string_cstr=connect_string->cstr(String::UL_UNSPECIFIED); | const char* connect_string_cstr=connect_string->cstr(String::UL_UNSPECIFIED); |
| const char* current=connect_string_cstr; | const char* current=connect_string_cstr; |
| if(strncmp(current, "http://", 7)!=0) | if(strncmp(current, "http://", 7)!=0) |
| throw Exception(0, | throw Exception(0, |
| Line 344 static HashStringValuePtr file_read_http | Line 355 static HashStringValuePtr file_read_http |
| if(valid_options!=options->count()) | if(valid_options!=options->count()) |
| throw Exception("parser.runtime", | throw Exception("parser.runtime", |
| Exception::undefined_source, | 0, |
| "invalid option passed"); | "invalid option passed"); |
| } | } |
| Line 372 static HashStringValuePtr file_read_http | Line 383 static HashStringValuePtr file_read_http |
| //sending request | //sending request |
| String response; | String response; |
| CharPtr request_cstr=request.cstr(String::UL_UNSPECIFIED); | const char* request_cstr=request.cstr(String::UL_UNSPECIFIED); |
| int status_code=http_request(pool, response, | int status_code=http_request(pool, response, |
| connect_string, host, port, request_cstr, | connect_string, host, port, request_cstr, |
| timeout, fail_on_status_ne_200); | timeout, fail_on_status_ne_200); |
| Line 384 static HashStringValuePtr file_read_http | Line 395 static HashStringValuePtr file_read_http |
| connect_string, | connect_string, |
| "bad response from host - no headers found"); | "bad response from host - no headers found"); |
| } | } |
| StringPtr header_block=response.mid(0, pos); | const String& header_block=response.mid(0, pos); |
| StringPtr body=response.mid(pos+4, response.size()); | const String& body=response.mid(pos+4, response.size()); |
| ArrayString aheaders; | ArrayString aheaders; |
| HashStringValuePtr headers(new HashStringValue); | result.headers=HashStringValue* (new HashStringValue); |
| header_block->split(aheaders, 0, "\r\n", 2); | header_block->split(aheaders, 0, "\r\n", 2); |
| //processing headers | //processing headers |
| for(int i=1; i<aheaders.count(); i++) { | for(int i=1; i<aheaders.count(); i++) { |
| StringPtr line=aheaders.get(i); | const String& line=aheaders.get(i); |
| pos=line->pos(": ", 2); | pos=line->pos(": ", 2); |
| if(pos<1) | if(pos<1) |
| throw Exception("http.response", | throw Exception("http.response", |
| connect_string, | connect_string, |
| "bad response from host - bad header \"%s\"", line->cstr().get()); | "bad response from host - bad header \"%s\"", line->cstr().get()); |
| headers->put( | result.headers->put( |
| line->mid(0, pos)->change_case(pool, charset, String::CC_UPPER), | line->mid(0, pos)->change_case(pool, charset, String::CC_UPPER), |
| ValuePtr(new VString(line->mid(pos+2, line->size())))); | ValuePtr(new VString(line->mid(pos+2, line->size())))); |
| } | } |
| // output response | // output response |
| data=new(pool) char[data_size=body->size()]; | result.data=new char[1/*as text puts terminating zero later*/+(result.size=body->size())]; |
| body->store_to(data, String::UL_AS_IS); | body->store_to(result.data, String::UL_AS_IS); |
| if(return_outfields) { | result.headers->put(file_status_name, ValuePtr(new VInt(status_code))); |
| headers->put(file_status_name, ValuePtr(new VInt(status_code))); | return result; |
| return headers; | |
| } else | |
| return HashStringValuePtr(0); | |
| } | } |
| #ifndef DOXYGEN | #ifndef DOXYGEN |
| Line 420 struct File_read_action_info { | Line 428 struct File_read_action_info { |
| char **data; size_t *data_size; | char **data; size_t *data_size; |
| }; | }; |
| #endif | #endif |
| static void file_read_action(Pool& pool, | static void file_read_action( |
| struct stat& finfo, | struct stat& finfo, |
| int f, | int f, |
| StringPtr 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) { | if(size_t to_read_size=(size_t)finfo.st_size) { |
| *info.data=pool.malloc(to_read_size+(as_text?1:0)); | *info.data=new 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 437 static void file_read_action(Pool& pool, | Line 445 static void file_read_action(Pool& pool, |
| *info.data_size, to_read_size); | *info.data_size, to_read_size); |
| } else { // empty file | } else { // empty file |
| if(as_text) { | if(as_text) { |
| *info.data=pool.malloc(1); | *info.data=new char[1]; |
| *(char*)(*info.data)=0; | *(char*)(*info.data)=0; |
| } else | } else |
| *info.data=0; | *info.data=0; |
| Line 445 static void file_read_action(Pool& pool, | Line 453 static void file_read_action(Pool& pool, |
| return; | return; |
| } | } |
| } | } |
| File_read_result file_read(Pool& pool, Charset& charset, StringPtr file_spec, | File_read_result file_readCharset& charset, const String& file_spec, |
| char*& data, size_t& data_size, | bool as_text, HashStringValue *params, |
| bool as_text, HashStringValue *params, HashStringValue** out_fields, | |
| bool fail_on_read_problem) { | bool fail_on_read_problem) { |
| File_read_result result; | File_read_result result; |
| if(file_spec->starts_with("http://", 7)) { | if(file_spec->starts_with("http://", 7)) { |
| // fail on read problem | // fail on read problem |
| result.fields=file_read_http(pool, charset, file_spec, data, data_size, params); | File_read_http_result http=file_read_http(pool, charset, file_spec, params); |
| result.success=true; | result.success=true; |
| result.data=http.data; | |
| result.size=http.size; | |
| result.headers=http.headers; | |
| } else { | } else { |
| File_read_action_info info={&data, &data_size}; | File_read_action_info info={&result.data, &result.size}; |
| result.success=file_read_action_under_lock(pool, file_spec, | result.success=file_read_action_under_lock(pool, 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 463 File_read_result file_read(Pool& pool, C | Line 473 File_read_result file_read(Pool& pool, C |
| if(result.success && as_text) { | if(result.success && as_text) { |
| // UTF-8 signature: EF BB BF | // UTF-8 signature: EF BB BF |
| if(data_size>=3) { | if(result.size>=3) { |
| char *in=(char *)data; | char *in=(char *)result.data; |
| if((in[0] == '\xEF') && (in[1] == '\xBB') && | if((in[0] == '\xEF') && (in[1] == '\xBB') && |
| (in[2] == '\xBF')) { | (in[2] == '\xBF')) { |
| data=in+3; data_size-=3;// skip prefix | result.data=in+3; result.size-=3;// skip prefix |
| } | } |
| } | } |
| fix_line_breaks((char *)(data), data_size); | fix_line_breaks((char *)(result.data), result.size); |
| // note: after fixing | // note: after fixing |
| ((char*&)(data))[data_size]=0; | ((char*&)(result.data))[result.size]=0; |
| } | } |
| return result; | return result; |
| } | } |
| bool file_read_action_under_lock(Pool& pool, StringPtr file_spec, | bool file_read_action_under_lockconst String& file_spec, |
| 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) { |
| CharPtr fname=file_spec->cstr(String::UL_FILE_SPEC); | const char* fname=file_spec->cstr(String::UL_FILE_SPEC); |
| int f; | int f; |
| // first open, next stat: | // first open, next stat: |
| Line 539 bool file_read_action_under_lock(Pool& p | Line 549 bool file_read_action_under_lock(Pool& p |
| } | } |
| } | } |
| static void create_dir_for_file(StringPtr file_spec) { | static void create_dir_for_file(const String& file_spec) { |
| size_t pos_after=1; | size_t pos_after=1; |
| int pos_before; | int pos_before; |
| while((pos_before=file_spec->pos("/", 1, pos_after))>=0) { | while((pos_before=file_spec->pos("/", 1, pos_after))>=0) { |
| Line 549 static void create_dir_for_file(StringPt | Line 559 static void create_dir_for_file(StringPt |
| } | } |
| bool file_write_action_under_lock( | bool file_write_action_under_lock( |
| StringPtr file_spec, | const String& file_spec, |
| const char* action_name, File_write_action action, void *context, | const char* action_name, File_write_action action, void *context, |
| bool as_text, | bool as_text, |
| bool do_append, | bool do_append, |
| bool do_block, | bool do_block, |
| bool fail_on_lock_problem) { | bool fail_on_lock_problem) { |
| CharPtr fname=file_spec->cstr(String::UL_FILE_SPEC); | const char* fname=file_spec->cstr(String::UL_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 602 bool file_write_action_under_lock( | Line 612 bool file_write_action_under_lock( |
| #ifndef DOXYGEN | #ifndef DOXYGEN |
| struct File_write_action_info { | struct File_write_action_info { |
| const void *data; size_t size; | const char *data; size_t size; |
| }; | }; |
| #endif | #endif |
| static void file_write_action(int f, void *context) { | static void file_write_action(int f, void *context) { |
| Line 611 static void file_write_action(int f, voi | Line 621 static void file_write_action(int f, voi |
| int written=write(f, info.data, info.size); | int written=write(f, info.data, info.size); |
| if(written<0) | if(written<0) |
| throw Exception(0, | throw Exception(0, |
| Exception::undefined_source, | 0, |
| "write failed: %s (%d)", strerror(errno), errno); | "write failed: %s (%d)", strerror(errno), errno); |
| } | } |
| } | } |
| void file_write( | void file_write( |
| StringPtr file_spec, | const String& file_spec, |
| const void *data, size_t size, | const char *data, size_t size, |
| bool as_text, | bool as_text, |
| bool do_append) { | bool do_append) { |
| File_write_action_info info={data, size}; | File_write_action_info info={data, size}; |
| Line 629 void file_write( | Line 639 void file_write( |
| } | } |
| // throws nothing! [this is required in file_move & file_delete] | // throws nothing! [this is required in file_move & file_delete] |
| static void rmdir(StringPtr file_spec, size_t pos_after) { | static void rmdir(const String& file_spec, size_t pos_after) { |
| int pos_before; | int pos_before; |
| if((pos_before=file_spec->pos("/", 1, pos_after))>=0) | if((pos_before=file_spec->pos("/", 1, pos_after))>=0) |
| rmdir(file_spec, pos_before+1); | rmdir(file_spec, pos_before+1); |
| rmdir(file_spec->mid(0, pos_after-1/* / */)->cstr(String::UL_FILE_SPEC)); | rmdir(file_spec->mid(0, pos_after-1/* / */)->cstr(String::UL_FILE_SPEC)); |
| } | } |
| bool file_delete(StringPtr file_spec, bool fail_on_read_problem) { | bool file_delete(const String& file_spec, bool fail_on_read_problem) { |
| CharPtr fname=file_spec->cstr(String::UL_FILE_SPEC); | const char* fname=file_spec->cstr(String::UL_FILE_SPEC); |
| if(unlink(fname)!=0) | if(unlink(fname)!=0) |
| if(fail_on_read_problem) | if(fail_on_read_problem) |
| throw Exception(errno==EACCES?"file.access":errno==ENOENT?"file.missing":0, | throw Exception(errno==EACCES?"file.access":errno==ENOENT?"file.missing":0, |
| Line 650 bool file_delete(StringPtr file_spec, bo | Line 660 bool file_delete(StringPtr file_spec, bo |
| rmdir(file_spec, 1); | rmdir(file_spec, 1); |
| return true; | return true; |
| } | } |
| void file_move(StringPtr old_spec, StringPtr new_spec) { | void file_move(const String& old_spec, const String& new_spec) { |
| CharPtr old_spec_cstr=old_spec->cstr(String::UL_FILE_SPEC); | const char* old_spec_cstr=old_spec->cstr(String::UL_FILE_SPEC); |
| CharPtr new_spec_cstr=new_spec->cstr(String::UL_FILE_SPEC); | const char* new_spec_cstr=new_spec->cstr(String::UL_FILE_SPEC); |
| create_dir_for_file(new_spec); | create_dir_for_file(new_spec); |
| Line 674 bool entry_exists(const char* fname, str | Line 684 bool entry_exists(const char* fname, str |
| return result; | return result; |
| } | } |
| bool entry_exists(StringPtr file_spec) { | bool entry_exists(const String& file_spec) { |
| CharPtr fname=file_spec->cstr(String::UL_FILE_SPEC); | const char* fname=file_spec->cstr(String::UL_FILE_SPEC); |
| return entry_exists(fname, 0); | return entry_exists(fname, 0); |
| } | } |
| static bool entry_readable(StringPtr file_spec, bool need_dir) { | static bool entry_readable(const String& file_spec, bool need_dir) { |
| CharPtr fname=file_spec->cstr(String::UL_FILE_SPEC); | const char* fname=file_spec->cstr(String::UL_FILE_SPEC); |
| if(need_dir) { | if(need_dir) { |
| size_t size=strlen(fname); | size_t size=strlen(fname); |
| while(size) { | while(size) { |
| Line 698 static bool entry_readable(StringPtr fil | Line 708 static bool entry_readable(StringPtr fil |
| } | } |
| return false; | return false; |
| } | } |
| bool file_readable(StringPtr file_spec) { | bool file_readable(const String& file_spec) { |
| return entry_readable(file_spec, false); | return entry_readable(file_spec, false); |
| } | } |
| bool dir_readable(StringPtr file_spec) { | bool dir_readable(const String& file_spec) { |
| return entry_readable(file_spec, true); | return entry_readable(file_spec, true); |
| } | } |
| StringPtr file_readable(StringPtr path, const String& name) { | const String& file_readable(String& path, String& name) { |
| StringPtr result(new String(*path)); | const String& result(new String(path)); |
| *result << "/"; | *result << "/"; |
| *result << name; | *result << name; |
| return file_readable(result)?result:StringPtr(0); | return file_readable(result)?result:0; |
| } | } |
| bool file_executable(StringPtr file_spec) { | bool file_executable(const String& file_spec) { |
| return access(file_spec->cstr(String::UL_FILE_SPEC), X_OK)==0; | return access(file_spec->cstr(String::UL_FILE_SPEC), X_OK)==0; |
| } | } |
| bool file_stat(StringPtr file_spec, | bool file_stat(const String& file_spec, |
| size_t& rsize, | size_t& rsize, |
| time_t& ratime, | time_t& ratime, |
| time_t& rmtime, | time_t& rmtime, |
| time_t& rctime, | time_t& rctime, |
| bool fail_on_read_problem) { | bool fail_on_read_problem) { |
| CharPtr fname=file_spec->cstr(String::UL_FILE_SPEC); | const char* fname=file_spec->cstr(String::UL_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 779 char* rsplit(char* string, char delim) { | Line 789 char* rsplit(char* string, char delim) { |
| } | } |
| /// @todo less stupid type detection | /// @todo less stupid type detection |
| const char* format(Pool& pool, double value, char* fmt) { | const char* formatdouble value, char* fmt) { |
| char local_buf[MAX_NUMBER]; | char local_buf[MAX_NUMBER]; |
| size_t size; | size_t size; |
| Line 813 size_t stdout_write(const void *buf, siz | Line 823 size_t stdout_write(const void *buf, siz |
| #endif | #endif |
| } | } |
| char* unescape_chars(Pool& pool, const char* cp, int len) { | char* unescape_charsconst char* cp, int len) { |
| char* s=pool.malloc(len + 1); | char* s=new char[len + 1]; |
| enum EscapeState { | enum EscapeState { |
| EscapeRest, | EscapeRest, |
| EscapeFirst, | EscapeFirst, |