Diff for /parser3/src/main/pa_http.C between versions 1.83 and 1.84

version 1.83, 2020/09/30 20:01:08 version 1.84, 2020/10/10 06:08:36
Line 96  static bool set_addr(struct sockaddr_in Line 96  static bool set_addr(struct sockaddr_in
         return false;          return false;
 }  }
   
 class HTTP_response {  class HTTP_response : public PA_Allocated {
 public:  public:
         char *buf;          char *buf;
         size_t length;          size_t length;
Line 104  public: Line 104  public:
         size_t body_offset;          size_t body_offset;
   
         ResponseHeaders headers;          ResponseHeaders headers;
         String &url;          const String &url;
   
         HTTP_response(String& aurl) : buf(NULL), length(0), buf_size(0), body_offset(0), url(aurl){}          HTTP_response(const String& aurl) : buf(NULL), length(0), buf_size(0), body_offset(0), url(aurl){}
   
         void resize(size_t size){          void resize(size_t size){
                 buf_size=size;                  buf_size=size;
Line 152  public: Line 152  public:
                         return status_line;                          return status_line;
   
                 const char *result_str=pa_strdup(status_start, status_end-status_start);                  const char *result_str=pa_strdup(status_start, status_end-status_start);
                 result=atoi(result_str);                  result=pa_atoui(result_str, 10);
                 return result_str;                  return result_str;
         }          }
   
Line 916  File_read_http_result pa_internal_file_r Line 916  File_read_http_result pa_internal_file_r
   
         return result;          return result;
 }  }
   
   /* ********************** httpd *************************** */
   
   class HTTPD_request : public HTTP_response {
   public:
           const char *method;
           const char *uri;
   
           HTTPD_request() : HTTP_response(String::Empty), method(NULL), uri(NULL){};
   
           const char *extract_method(char *method_line){
                   char* uri_start = strchr(method_line, ' ');
   
                   if(!uri_start || uri_start == method_line)
                           return NULL;
   
                   char* uri_end=strchr(uri_start+1, ' ');
   
                   if(!uri_end || uri_end == uri_start+1)
                           return NULL;
   
                   uri=pa_strdup(uri_start+1, uri_end-uri_start-1);
                   return str_upper(method_line, uri_start-method_line);
           }
   
           void read_header(int sock);
   };
   
   enum HTTPD_request_state {
           HTTPD_METHOD,
           HTTPD_HEADERS
   };
   
   void HTTPD_request::read_header(int sock) {
           enum HTTPD_request_state state = HTTPD_METHOD;
   
           size_t chunk_size = 0x400*4;
           resize(chunk_size);
   
           while(read(sock, chunk_size)){
                   switch(state){
                           case HTTPD_METHOD: {
                                   size_t method_size = first_line();
                                   if(!method_size)
                                           break;
   
                                   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"))
                                           throw Exception("httpd.method", new String(method ? method : method_line), "invalid request method");
                                   state = HTTPD_HEADERS;
                           }
   
                           case HTTPD_HEADERS: {
                                   if(!body_start())
                                           break;
   
                                   parse_headers();
                                   return;
                           }
                   }
           }
   
           if(state == HTTPD_METHOD)
                   throw Exception("httpd.request", 0, "bad request from host - no method found (size=%u)", length);
   
           if(state == HTTPD_HEADERS){
                   parse_headers();
                   body_offset=length;
           }
   }
   
   /* ********************************************************** */
   
   Array<ResponseHeaders::Header> &HTTPD_Connection::headers() {
           return request->headers.headers;
   }
   
   const char *HTTPD_Connection::method() {
           return request->method;
   }
   
   const char *HTTPD_Connection::uri() {
           return request->uri;
   }
   
   const char *HTTPD_Connection::content_type() {
           return request->headers.content_type.cstr();
   }
   
   uint64_t HTTPD_Connection::content_length(){
           return request->headers.content_length;
   }
   
   void HTTPD_Connection::read_header(){
           request = new HTTPD_request();
           request->read_header(sock);
   }
   
   static int sock_on = 1;
   
   int HTTPD_Server::bind(const char *host, int port){
           struct sockaddr_in me;
   
           if(!set_addr(&me, host, port)){
                   if (host)
                           throw Exception("httpd.bind", 0, "can not resolve hostname \"%s\"", host);
                   me.sin_addr.s_addr=INADDR_ANY;
           }
   
           int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP/*0*/);
   
           if(sock < 0){
                   int no=pa_socks_errno();
                   throw Exception("httpd.bind", 0, "can not make socket: %s (%d)", pa_socks_strerr(no), no);
           }
   
           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)) ||
               listen(sock, 16)) {
                   close(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){
           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;
           unsigned int 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)));
   }
   

Removed from v.1.83  
changed lines
  Added in v.1.84


E-mail: