|
|
| version 1.121, 2023/09/26 20:49:10 | version 1.129, 2024/11/04 03:53:25 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: http support functions. | Parser: http support functions. |
| Copyright (c) 2001-2023 Art. Lebedev Studio (http://www.artlebedev.com) | Copyright (c) 2001-2024 Art. Lebedev Studio (http://www.artlebedev.com) |
| Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru> | Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru> |
| */ | */ |
| Line 173 public: | Line 173 public: |
| ArrayString aheaders; | ArrayString aheaders; |
| header_block.split(aheaders, 0, "\n"); | header_block.split(aheaders, 0, "\n"); |
| Array_iterator<const String*> i(aheaders); | ArrayString::Iterator i(aheaders); |
| i.next(); // skipping status | i.next(); // skipping status |
| for(;i.has_next();){ | for(;i;){ |
| const char *line=i.next()->cstr(); | const char *line=i.next()->cstr(); |
| if(!headers.add_header(line)) | if(!headers.add_header(line)) |
| throw Exception("http.response", 0, "bad response from host - bad header \"%s\"", line); | throw Exception("http.response", 0, "bad response from host - bad header \"%s\"", line); |
| Line 288 static int http_request(HTTP_response& r | Line 288 static int http_request(HTTP_response& r |
| struct sockaddr_in dest; | struct sockaddr_in dest; |
| if(!set_addr(&dest, host, port)) | if(!set_addr(&dest, host, port)) |
| throw Exception("http.host", 0, "can not resolve hostname \"%s\"", host); | throw Exception("http.host", 0, "cannot resolve hostname \"%s\"", host); |
| if((sock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP/*0*/)) == INVALID_SOCKET) { | if((sock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP/*0*/)) == INVALID_SOCKET) { |
| int no=pa_socks_errno(); | int no=pa_socks_errno(); |
| throw Exception("http.connect", 0, "can not make socket: %s (%d)", pa_socks_strerr(no), no); | throw Exception("http.connect", 0, "cannot make socket: %s (%d)", pa_socks_strerr(no), no); |
| } | } |
| // To enable SO_DONTLINGER (that is, disable SO_LINGER) | // To enable SO_DONTLINGER (that is, disable SO_LINGER) |
| Line 311 static int http_request(HTTP_response& r | Line 311 static int http_request(HTTP_response& r |
| if(connect(sock, (struct sockaddr *)&dest, sizeof(dest))) { | if(connect(sock, (struct sockaddr *)&dest, sizeof(dest))) { |
| int no=pa_socks_errno(); | int no=pa_socks_errno(); |
| throw Exception("http.connect", 0, "can not connect to host \"%s\": %s (%d)", host, pa_socks_strerr(no), no); | throw Exception("http.connect", 0, "cannot connect to host \"%s\": %s (%d)", host, pa_socks_strerr(no), no); |
| } | } |
| if(send(sock, request, request_size, 0)!=(ssize_t)request_size) { | if(send(sock, request, request_size, 0)!=(ssize_t)request_size) { |
| Line 511 static void form_value2part(HashStringVa | Line 511 static void form_value2part(HashStringVa |
| Form_table_value2string_info info(key, *part.string); | Form_table_value2string_info info(key, *part.string); |
| part.info = &info; | part.info = &info; |
| tvalue->for_each(form_table_value2part, &part); | tvalue->for_each(form_table_value2part, &part); |
| } else if(VFile* vfile=static_cast<VFile *>(value->as("file"))){ | } else if(VFile* vfile=dynamic_cast<VFile *>(value)){ |
| form_file_value2part(key, *vfile, part); | form_file_value2part(key, *vfile, part); |
| } else | } else |
| throw Exception(PARSER_RUNTIME, new String(key, String::L_TAINTED), "is %s, " HTTP_FORM_NAME " option value can be string, table or file only", value->type()); | throw Exception(PARSER_RUNTIME, new String(key, String::L_TAINTED), "is %s, " HTTP_FORM_NAME " option value can be string, table or file only", value->type()); |
| Line 551 static ArrayString* parse_cookie(Request | Line 551 static ArrayString* parse_cookie(Request |
| if(first_pair) { | if(first_pair) { |
| // name + value | // name + value |
| name=sname; | name=sname; |
| value=smeaning; | if(smeaning) |
| value=smeaning; | |
| first_pair=false; | first_pair=false; |
| } else { | } else { |
| const String& slower=sname->change_case(r.charsets.source(), String::CC_LOWER); | const String& slower=sname->change_case(r.charsets.source(), String::CC_LOWER); |
| Line 594 static ArrayString* parse_cookie(Request | Line 595 static ArrayString* parse_cookie(Request |
| Table* parse_cookies(Request& r, Table *cookies){ | Table* parse_cookies(Request& r, Table *cookies){ |
| Table& result=*new Table(new Cookies_table_template_columns); | Table& result=*new Table(new Cookies_table_template_columns); |
| for(Array_iterator<Table::element_type> i(*cookies); i.has_next(); ) | for(Array_iterator<Table::element_type> i(*cookies); i; ) |
| if(ArrayString* row=parse_cookie(r, *i.next()->get(0))) | if(ArrayString* row=parse_cookie(r, *i.next()->get(0))) |
| result+=row; | result+=row; |
| Line 703 File_read_http_result pa_internal_file_r | Line 704 File_read_http_result pa_internal_file_r |
| if(encode){ | if(encode){ |
| if(method_is_get) | if(method_is_get) |
| throw Exception(PARSER_RUNTIME, 0, "you can not use $." HTTP_FORM_ENCTYPE_NAME " option with method GET"); | throw Exception(PARSER_RUNTIME, 0, "you cannot use $." HTTP_FORM_ENCTYPE_NAME " option with method GET"); |
| multipart=strcasecmp(encode, HTTP_CONTENT_TYPE_MULTIPART_FORMDATA)==0; | multipart=strcasecmp(encode, HTTP_CONTENT_TYPE_MULTIPART_FORMDATA)==0; |
| Line 713 File_read_http_result pa_internal_file_r | Line 714 File_read_http_result pa_internal_file_r |
| if(vbody){ | if(vbody){ |
| if(method_is_get) | if(method_is_get) |
| throw Exception(PARSER_RUNTIME, 0, "you can not use $." HTTP_BODY_NAME " option with method GET"); | throw Exception(PARSER_RUNTIME, 0, "you cannot use $." HTTP_BODY_NAME " option with method GET"); |
| if(form) | if(form) |
| throw Exception(PARSER_RUNTIME, 0, "you can not use options $." HTTP_BODY_NAME " and $." HTTP_FORM_NAME " together"); | throw Exception(PARSER_RUNTIME, 0, "you cannot use options $." HTTP_BODY_NAME " and $." HTTP_FORM_NAME " together"); |
| } | } |
| //preparing request | //preparing request |
| Line 831 File_read_http_result pa_internal_file_r | Line 832 File_read_http_result pa_internal_file_r |
| } | } |
| if(request_body) | if(request_body) |
| head << "Content-Length: " << format(post_size, "%u") << CRLF; | head << "Content-Length: " << pa_uitoa(post_size) << CRLF; |
| head << CRLF; | head << CRLF; |
| Line 874 File_read_http_result pa_internal_file_r | Line 875 File_read_http_result pa_internal_file_r |
| if (!real_remote_charset) | if (!real_remote_charset) |
| real_remote_charset=asked_remote_charset; // never null | real_remote_charset=asked_remote_charset; // never null |
| for(Array_iterator<HTTP_Headers::Header> i(response.headers.headers); i.has_next(); ){ | for(Array_iterator<HTTP_Headers::Header> i(response.headers.headers); i; ){ |
| HTTP_Headers::Header header=i.next(); | HTTP_Headers::Header header=i.next(); |
| header.transcode(*real_remote_charset, r.charsets.source()); | header.transcode(*real_remote_charset, r.charsets.source()); |
| Line 1217 bool HTTPD_Connection::accept(SOCKET ser | Line 1218 bool HTTPD_Connection::accept(SOCKET ser |
| throw Exception("httpd.accept", 0, "error accepting connection: %s (%d)", pa_socks_strerr(no), no); | throw Exception("httpd.accept", 0, "error accepting connection: %s (%d)", pa_socks_strerr(no), no); |
| } | } |
| // Has no positive performance effect, requires include <netinet/tcp.h> | |
| // static int sock_on=1; | |
| // setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&sock_on, sizeof(sock_on)); | |
| remote_addr = pa_strdup(inet_ntoa(addr.sin_addr)); | remote_addr = pa_strdup(inet_ntoa(addr.sin_addr)); |
| LOG(pa_log("httpd [%d] accepted from %s", sock, remote_addr)); | LOG(pa_log("httpd [%d] accepted from %s", sock, remote_addr)); |
| return true; | return true; |
| Line 1253 SOCKET HTTPD_Server::bind(const char *ho | Line 1258 SOCKET HTTPD_Server::bind(const char *ho |
| if(!set_addr(&me, host, (short)pa_atoui(port))){ | if(!set_addr(&me, host, (short)pa_atoui(port))){ |
| if (host) | if (host) |
| throw Exception("httpd.bind", 0, "can not resolve hostname \"%s\"", host); | throw Exception("httpd.bind", 0, "cannot resolve hostname \"%s\"", host); |
| me.sin_addr.s_addr=INADDR_ANY; | me.sin_addr.s_addr=INADDR_ANY; |
| } | } |
| Line 1261 SOCKET HTTPD_Server::bind(const char *ho | Line 1266 SOCKET HTTPD_Server::bind(const char *ho |
| if(sock == INVALID_SOCKET){ | if(sock == INVALID_SOCKET){ |
| int no=pa_socks_errno(); | int no=pa_socks_errno(); |
| throw Exception("httpd.bind", 0, "can not make socket: %s (%d)", pa_socks_strerr(no), no); | throw Exception("httpd.bind", 0, "cannot make socket: %s (%d)", pa_socks_strerr(no), no); |
| } | } |
| static int sock_on = 1; | static int sock_on = 1; |
| Line 1272 SOCKET HTTPD_Server::bind(const char *ho | Line 1277 SOCKET HTTPD_Server::bind(const char *ho |
| listen(sock, 16)) { | listen(sock, 16)) { |
| closesocket(sock); | closesocket(sock); |
| int no = pa_socks_errno(); | int no = pa_socks_errno(); |
| throw Exception("httpd.bind", 0, "can not bind socket: %s (%d)", pa_socks_strerr(no), no); | throw Exception("httpd.bind", 0, "cannot bind socket: %s (%d)", pa_socks_strerr(no), no); |
| } | } |
| return sock; | return sock; |
| } | } |