--- parser3/src/main/pa_http.C 2020/10/12 21:57:20 1.91 +++ parser3/src/main/pa_http.C 2020/10/14 21:35:00 1.97 @@ -14,7 +14,7 @@ #include "pa_vfile.h" #include "pa_random.h" -volatile const char * IDENT_PA_HTTP_C="$Id: pa_http.C,v 1.91 2020/10/12 21:57:20 moko Exp $" IDENT_PA_HTTP_H; +volatile const char * IDENT_PA_HTTP_C="$Id: pa_http.C,v 1.97 2020/10/14 21:35:00 moko Exp $" IDENT_PA_HTTP_H; #ifdef _MSC_VER #include @@ -59,7 +59,7 @@ bool HTTP_Headers::add_header(const char content_type=header.value; if(header.name == String::Body("CONTENT-LENGTH") && content_length==0) - content_length=pa_atoul(header.value.cstr(), 10); + ALTER_EXCEPTION_COMMENT(content_length=pa_atoul(header.value.cstr()), " for content-length"); headers+=header; @@ -105,9 +105,8 @@ public: size_t body_offset; HTTP_Headers headers; - const String &url; - HTTP_response(const String& aurl) : buf(NULL), length(0), buf_size(0), body_offset(0), url(aurl){} + HTTP_response() : buf(NULL), length(0), buf_size(0), body_offset(0){} void resize(size_t size){ buf_size=size; @@ -122,7 +121,7 @@ public: return false; if(received_size<0) { if(int no=pa_socks_errno()) - throw Exception("http.timeout", &url, "error receiving response body: %s (%d)", pa_socks_strerr(no), no); + throw Exception("http.timeout", 0, "error receiving response body: %s (%d)", pa_socks_strerr(no), no); return false; } length+=received_size; @@ -153,7 +152,7 @@ public: return status_line; const char *result_str=pa_strdup(status_start, status_end-status_start); - result=pa_atoui(result_str, 10); + ALTER_EXCEPTION_COMMENT(result=pa_atoui(result_str), " for HTTP status"); return result_str; } @@ -186,7 +185,7 @@ public: for(;i.has_next();){ const char *line=i.next()->cstr(); if(!headers.add_header(line)) - throw Exception("http.response", &url, "bad response from host - bad header \"%s\"", line); + throw Exception("http.response", 0, "bad response from host - bad header \"%s\"", line); } } @@ -227,7 +226,7 @@ int HTTP_response::read_response(int soc parse_headers(); - size_t content_length=check_file_size(headers.content_length, url); + size_t content_length=check_file_size(headers.content_length, 0); if(content_length>0 && (content_length + body_offset) > length){ resize(content_length + body_offset + 0x400*64); } @@ -244,7 +243,7 @@ int HTTP_response::read_response(int soc } if(state==HTTP_STATUS_CODE) - throw Exception("http.response", &url, "bad response from host - no status found (size=%u)", length); + throw Exception("http.response", 0, "bad response from host - no status found (size=%u)", length); if(state==HTTP_HEADERS){ parse_headers(); @@ -864,10 +863,11 @@ File_read_http_result pa_internal_file_r } - HTTP_response response(connect_string); + HTTP_response response; // sending request - int status_code=http_request(response, idna_host, port, request, request_size, timeout_secs, fail_on_status_ne_200); + int status_code; + ALTER_EXCEPTION_SOURCE(status_code=http_request(response, idna_host, port, request, request_size, timeout_secs, fail_on_status_ne_200), &connect_string); // processing results char* raw_body=response.buf + response.body_offset; @@ -926,7 +926,7 @@ public: const char *method; const char *uri; - HTTPD_request() : HTTP_response(String::Empty), method(NULL), uri(NULL){}; + HTTPD_request() : HTTP_response(), method(NULL), uri(NULL){}; const char *extract_method(char *method_line){ char* uri_start = strchr(method_line, ' '); @@ -968,7 +968,14 @@ void HTTPD_request::read_header(int sock char *method_line = pa_strdup(buf, method_size); method = extract_method(method_line); - if(!method || strcmp(method, "GET") && strcmp(method, "HEAD") && strcmp(method, "POST") && strcmp(method, "PUT") && strcmp(method, "DELETE")) + if(!method || + strcmp(method, "GET") && + strcmp(method, "HEAD") && + strcmp(method, "POST") && + strcmp(method, "PUT") && + strcmp(method, "DELETE") && + strcmp(method, "PATCH") + ) throw Exception("httpd.method", new String(method ? method : method_line), "invalid request method"); state = HTTPD_HEADERS; } @@ -1002,7 +1009,7 @@ size_t HTTPD_request::read_post(int sock return total_read; if(received_size < 0) { if(int no = pa_socks_errno()) - throw Exception("httpd.timeout", &url, "error receiving request body: %s (%d)", pa_socks_strerr(no), no); + throw Exception("httpd.timeout", new String(uri), "error receiving request body: %s (%d)", pa_socks_strerr(no), no); return total_read; } total_read += received_size; @@ -1049,7 +1056,47 @@ size_t HTTPD_Connection::send_body(const return size; } -static int sock_on = 1; +HTTPD_Connection::~HTTPD_Connection(){ + if(sock != -1) + closesocket(sock); +} + +static int sock_ready(int fd,int operation,int timeout_value){ + struct timeval timeout = {0, timeout_value * 1000}; + fd_set fds; + FD_ZERO(&fds); + FD_SET(fd, &fds); + switch (operation){ + case 0: return select(fd + 1, &fds, NULL, NULL, &timeout)>0; /* read */ + case 1: return select(fd + 1, NULL, &fds, NULL, &timeout)>0; /* write */ + default: return select(fd + 1, &fds, &fds, NULL, &timeout)>0; /* both */ + } +} + +bool HTTPD_Connection::accept(int server_sock, int timeout_value) { + int ready = sock_ready(server_sock, 0, timeout_value); + if (ready < 0) { + int no=pa_socks_errno(); + if(no == EINTR) + return false; + throw Exception("httpd.accept", 0, "error waiting for connection: %s (%d)", pa_socks_strerr(no), no); + } + if (ready == 0) + return false; /* Timeout */ + + struct sockaddr_in addr; + socklen_t sock_addr_len = sizeof(struct sockaddr_in); + memset(&addr, 0, sock_addr_len); + + sock = ::accept(server_sock, (struct sockaddr *)&addr, &sock_addr_len); + if(server_sock == -1){ + int no=pa_socks_errno(); + throw Exception("httpd.accept", 0, "error accepting connection: %s (%d)", pa_socks_strerr(no), no); + } + + remote_addr = pa_strdup(inet_ntoa(addr.sin_addr)); + return true; +} int HTTPD_Server::bind(const char *host_port){ struct sockaddr_in me; @@ -1063,7 +1110,7 @@ int HTTPD_Server::bind(const char *host_ port = host_port; } - if(!set_addr(&me, host, pa_atoui(port, 10))){ + if(!set_addr(&me, host, pa_atoui(port))){ if (host) throw Exception("httpd.bind", 0, "can not resolve hostname \"%s\"", host); me.sin_addr.s_addr=INADDR_ANY; @@ -1076,6 +1123,8 @@ int HTTPD_Server::bind(const char *host_ throw Exception("httpd.bind", 0, "can not make socket: %s (%d)", pa_socks_strerr(no), no); } + static int sock_on = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&sock_on, sizeof(sock_on)) || setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&sock_on, sizeof(sock_on)) || ::bind(sock, (struct sockaddr*)&me, sizeof(me)) || @@ -1086,42 +1135,3 @@ int HTTPD_Server::bind(const char *host_ } return sock; } - -static int ready(int fd,int operation,int timeout_value){ - struct timeval timeout = {0, timeout_value * 1000}; - fd_set fds; - FD_ZERO(&fds); - FD_SET(fd, &fds); - switch (operation){ - case 0: return select(fd + 1, &fds, NULL, NULL, &timeout)>0; /* read */ - case 1: return select(fd + 1, NULL, &fds, NULL, &timeout)>0; /* write */ - default: return select(fd + 1, &fds, &fds, NULL, &timeout)>0; /* both */ - } -} - -HTTPD_Connection *HTTPD_Server::accept(int sock, int timeout_value) { - int ready = ::ready(sock, 0, timeout_value); - if (ready < 0) { - int no=pa_socks_errno(); - if(no == EINTR) - return NULL; - throw Exception("httpd.accept", 0, "error waiting for connection: %s (%d)", pa_socks_strerr(no), no); - } - if (ready == 0) { - /* Timeout */ - return NULL; - } - - struct sockaddr_in addr; - socklen_t sock_addr_len = sizeof(struct sockaddr_in); - memset(&addr, 0, sock_addr_len); - - int csock = ::accept(sock, (struct sockaddr *)&addr, &sock_addr_len); - if(csock == -1){ - int no=pa_socks_errno(); - throw Exception("httpd.accept", 0, "error accepting connection: %s (%d)", pa_socks_strerr(no), no); - } - - return new HTTPD_Connection(csock, pa_strdup(inet_ntoa(addr.sin_addr))); -} -