--- parser3/src/main/pa_http.C 2020/10/10 06:08:36 1.84 +++ parser3/src/main/pa_http.C 2020/10/12 21:55:17 1.90 @@ -14,10 +14,11 @@ #include "pa_vfile.h" #include "pa_random.h" -volatile const char * IDENT_PA_HTTP_C="$Id: pa_http.C,v 1.84 2020/10/10 06:08:36 moko Exp $" IDENT_PA_HTTP_H; +volatile const char * IDENT_PA_HTTP_C="$Id: pa_http.C,v 1.90 2020/10/12 21:55:17 moko Exp $" IDENT_PA_HTTP_H; #ifdef _MSC_VER #include +#define socklen_t int #else #define closesocket close #endif @@ -48,7 +49,7 @@ volatile const char * IDENT_PA_HTTP_C="$ // helpers -bool ResponseHeaders::add_header(const char *line){ +bool HTTP_Headers::add_header(const char *line){ const char *value=strchr(line, ':'); if(value && value != line){ // we need only headers, not the response code @@ -103,7 +104,7 @@ public: size_t buf_size; size_t body_offset; - ResponseHeaders headers; + HTTP_Headers headers; const String &url; HTTP_response(const String& aurl) : buf(NULL), length(0), buf_size(0), body_offset(0), url(aurl){} @@ -130,11 +131,11 @@ public: } size_t first_line(){ - char *headers=strchr(buf, '\n'); - if(!headers) + char *header=strchr(buf, '\n'); + if(!header) return false; - return headers-buf; + return header-buf; } const char *status_code(char *status_line, int &result){ @@ -189,6 +190,7 @@ public: } } + int read_response(int sock, bool fail_on_status_ne_200); }; enum HTTP_response_state { @@ -197,21 +199,21 @@ enum HTTP_response_state { HTTP_BODY }; -static int http_read_response(HTTP_response& response, int sock, bool fail_on_status_ne_200) { +int HTTP_response::read_response(int sock, bool fail_on_status_ne_200) { HTTP_response_state state=HTTP_STATUS_CODE; int result=0; size_t chunk_size=0x400*16; - response.resize(2*chunk_size); + resize(2*chunk_size); - while(response.read(sock, chunk_size)){ + while(read(sock, chunk_size)){ switch(state){ case HTTP_STATUS_CODE: { - size_t status_size=response.first_line(); + size_t status_size=first_line(); if(!status_size) break; - const char *status=response.status_code(pa_strdup(response.buf, status_size), result); + const char *status=status_code(pa_strdup(buf, status_size), result); if(!result || fail_on_status_ne_200 && result!=200) throw Exception("http.status", status ? new String(status) : &String::Empty, "invalid HTTP response status"); @@ -220,14 +222,14 @@ static int http_read_response(HTTP_respo } case HTTP_HEADERS: { - if(!response.body_start()) + if(!body_start()) break; - response.parse_headers(); + parse_headers(); - size_t content_length=check_file_size(response.headers.content_length, response.url); - if(content_length>0 && (content_length + response.body_offset) > response.length){ - response.resize(content_length + response.body_offset + 0x400*64); + size_t content_length=check_file_size(headers.content_length, url); + if(content_length>0 && (content_length + body_offset) > length){ + resize(content_length + body_offset + 0x400*64); } state=HTTP_BODY; @@ -242,11 +244,11 @@ static int http_read_response(HTTP_respo } if(state==HTTP_STATUS_CODE) - throw Exception("http.response", &response.url, "bad response from host - no status found (size=%u)", response.length); + throw Exception("http.response", &url, "bad response from host - no status found (size=%u)", length); if(state==HTTP_HEADERS){ - response.parse_headers(); - response.body_offset=response.length; + parse_headers(); + body_offset=length; } return result; @@ -322,7 +324,7 @@ static int http_request(HTTP_response& r throw Exception("http.timeout", 0, "error sending request: %s (%d)", pa_socks_strerr(no), no); } - result=http_read_response(response, sock, fail_on_status_ne_200); + result=response.read_response(sock, fail_on_status_ne_200); closesocket(sock); #ifdef PA_USE_ALARM alarm(0); @@ -884,8 +886,8 @@ File_read_http_result pa_internal_file_r if (!real_remote_charset) real_remote_charset=asked_remote_charset; // never null - for(Array_iterator i(response.headers.headers); i.has_next(); ){ - ResponseHeaders::Header header=i.next(); + for(Array_iterator i(response.headers.headers); i.has_next(); ){ + HTTP_Headers::Header header=i.next(); header.transcode(*real_remote_charset, r.charsets.source()); @@ -896,7 +898,7 @@ File_read_http_result pa_internal_file_r } // filling $.cookies - if(Value *vcookies=vtables->hash().get("SET-COOKIE")) + if(vcookies=vtables->hash().get("SET-COOKIE")) result.headers->put(HTTP_COOKIES_NAME, new VTable(parse_cookies(r, vcookies->get_table()))); // output response @@ -941,7 +943,8 @@ public: return str_upper(method_line, uri_start-method_line); } - void read_header(int sock); + void read_header(int); + size_t read_post(int, char *, size_t); }; enum HTTPD_request_state { @@ -989,9 +992,27 @@ void HTTPD_request::read_header(int sock } } +size_t HTTPD_request::read_post(int sock, char *body, size_t max_bytes) { + size_t total_read = min(length - body_offset, max_bytes); + memcpy(body, buf, total_read); + + while (total_read < max_bytes){ + ssize_t received_size = recv(sock, buf + total_read, max_bytes - total_read, 0); + if(received_size == 0) + 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); + return total_read; + } + total_read += received_size; + } + return total_read; +} + /* ********************************************************** */ -Array &HTTPD_Connection::headers() { +Array &HTTPD_Connection::headers() { return request->headers.headers; } @@ -1016,12 +1037,33 @@ void HTTPD_Connection::read_header(){ request->read_header(sock); } +size_t HTTPD_Connection::read_post(char *body, size_t max_bytes) { + return request->read_post(sock, body, max_bytes); +} + +size_t HTTPD_Connection::send_body(const void *buf, size_t size) { + if(send(sock, buf, size, 0) != (ssize_t)size) { + int no=pa_socks_errno(); + throw Exception("httpd.timeout", 0, "error sending response: %s (%d)", pa_socks_strerr(no), no); + } + return size; +} + static int sock_on = 1; -int HTTPD_Server::bind(const char *host, int port){ +int HTTPD_Server::bind(const char *host_port){ struct sockaddr_in me; - if(!set_addr(&me, host, port)){ + const char *port = strchr(host_port, ':'); + const char *host = NULL; + if(port && port > host_port){ + host = pa_strdup(host_port, port - host_port); + port += 1; + } else { + port = host_port; + } + + if(!set_addr(&me, host, pa_atoui(port, 10))){ if (host) throw Exception("httpd.bind", 0, "can not resolve hostname \"%s\"", host); me.sin_addr.s_addr=INADDR_ANY; @@ -1038,14 +1080,14 @@ int HTTPD_Server::bind(const char *host, setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&sock_on, sizeof(sock_on)) || ::bind(sock, (struct sockaddr*)&me, sizeof(me)) || listen(sock, 16)) { - close(sock); + closesocket(sock); int no = pa_socks_errno(); throw Exception("httpd.bind", 0, "can not bind socket: %s (%d)", pa_socks_strerr(no), no); } return sock; } -int ready(int fd,int operation,int timeout_value){ +static int ready(int fd,int operation,int timeout_value){ struct timeval timeout = {0, timeout_value * 1000}; fd_set fds; FD_ZERO(&fds); @@ -1057,9 +1099,7 @@ int ready(int fd,int operation,int timeo } } - 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(); @@ -1073,7 +1113,7 @@ HTTPD_Connection *HTTPD_Server::accept(i } struct sockaddr_in addr; - unsigned int sock_addr_len = sizeof(struct sockaddr_in); + 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);