static void handle_read( connecttab* c, struct timeval* tvP ) { int sz; httpd_conn* hc = c->hc; /* Is there room in our buffer to read more bytes? */ if ( hc->read_idx >= hc->read_size ) { if ( hc->read_size > 5000 ) { httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); finish_connection( c, tvP ); return; } httpd_realloc_str( &hc->read_buf, &hc->read_size, hc->read_size + 1000 ); } /* Read some more bytes. */ sz = read( hc->conn_fd, &(hc->read_buf[hc->read_idx]), hc->read_size - hc->read_idx ); if ( sz == 0 ) { httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); finish_connection( c, tvP ); return; } if ( sz < 0 ) { /* Ignore EINTR and EAGAIN. Also ignore EWOULDBLOCK. At first glance ** you would think that connections returned by fdwatch as readable ** should never give an EWOULDBLOCK; however, this apparently can ** happen if a packet gets garbled. */ if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) return; httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); finish_connection( c, tvP ); return; } hc->read_idx += sz; c->active_at = tvP->tv_sec; /* Do we have a complete request yet? */ switch ( httpd_got_request( hc ) ) { case GR_NO_REQUEST: return; case GR_BAD_REQUEST: httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); finish_connection( c, tvP ); return; } /* Yes. Try parsing and resolving it. */ if ( httpd_parse_request( hc ) < 0 ) { finish_connection( c, tvP ); return; } /* Start the connection going. */ if ( httpd_start_request( hc, tvP ) < 0 ) { /* Something went wrong. Close down the connection. */ finish_connection( c, tvP ); return; } if ( c->conn_state == CNST_SLEEPING ) { return; } handle_read_2( c, tvP ); }
static void handle_read(struct connect_s *conn, struct timeval *tv) { ClientData client_data; httpd_conn *hc = conn->hc; off_t actual; int sz; /* Is there room in our buffer to read more bytes? */ if (hc->read_idx >= hc->read_size) { if (hc->read_size > CONFIG_THTTPD_MAXREALLOC) { BADREQUEST("MAXREALLOC"); goto errout_with_400; } httpd_realloc_str(&hc->read_buf, &hc->read_size, hc->read_size + CONFIG_THTTPD_REALLOCINCR); } /* Read some more bytes */ sz = read(hc->conn_fd, &(hc->read_buf[hc->read_idx]), hc->read_size - hc->read_idx); if (sz == 0) { BADREQUEST("EOF"); goto errout_with_400; } if (sz < 0) { /* Ignore EINTR and EAGAIN. Also ignore EWOULDBLOCK. At first glance * you would think that connections returned by fdwatch as readable * should never give an EWOULDBLOCK; however, this apparently can * happen if a packet gets garbled. */ if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) { return; } ndbg("read(fd=%d) failed: %d\n", hc->conn_fd, errno); BADREQUEST("read"); goto errout_with_400; } hc->read_idx += sz; conn->active_at = tv->tv_sec; /* Do we have a complete request yet? */ switch (httpd_got_request(hc)) { case GR_NO_REQUEST: return; case GR_BAD_REQUEST: BADREQUEST("httpd_got_request"); goto errout_with_400; } /* Yes. Try parsing and resolving it */ if (httpd_parse_request(hc) < 0) { goto errout_with_connection; } /* Start the connection going */ if (httpd_start_request(hc, tv) < 0) { /* Something went wrong. Close down the connection */ goto errout_with_connection; } /* Set up the file offsets to read */ conn->eof = false; if (hc->got_range) { conn->offset = hc->range_start; conn->end_offset = hc->range_end + 1; } else { conn->offset = 0; if (hc->bytes_to_send < 0) { conn->end_offset = 0; } else { conn->end_offset = hc->bytes_to_send; } } /* Check if it's already handled */ if (hc->file_fd < 0) { /* No file descriptor means someone else is handling it */ conn->offset = hc->bytes_sent; goto errout_with_connection; } if (conn->offset >= conn->end_offset) { /* There's nothing to send */ goto errout_with_connection; } /* Seek to the offset of the next byte to send */ actual = lseek(hc->file_fd, conn->offset, SEEK_SET); if (actual != conn->offset) { ndbg("fseek to %d failed: offset=%d errno=%d\n", conn->offset, actual, errno); BADREQUEST("lseek"); goto errout_with_400; } /* We have a valid connection and a file to send to it */ conn->conn_state = CNST_SENDING; client_data.p = conn; fdwatch_del_fd(fw, hc->conn_fd); return; errout_with_400: BADREQUEST("errout"); httpd_send_err(hc, 400, httpd_err400title, "", httpd_err400form, ""); errout_with_connection: finish_connection(conn, tv); return; }
static void handle_read( connecttab* c, struct timeval* tvP ) { int sz; ClientData client_data; httpd_conn* hc = c->hc; /* Is there room in our buffer to read more bytes? */ if ( hc->read_idx >= hc->read_size ) { if ( hc->read_size > 5000 ) { httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); clear_connection( c, tvP ); return; } httpd_realloc_str( &hc->read_buf, &hc->read_size, hc->read_size + 1000 ); } /* Read some more bytes. */ sz = read( hc->conn_fd, &(hc->read_buf[hc->read_idx]), hc->read_size - hc->read_idx ); /* Ignore EWOULDBLOCK errors. At first glance you would think that ** connections returned by fdwatch as readable should never give an ** EWOULDBLOCK; however, this apparently can happen if a packet gets ** garbled. */ if ( sz == 0 || ( sz < 0 && ( errno != EWOULDBLOCK ) ) ) { httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); clear_connection( c, tvP ); return; } hc->read_idx += sz; /* Do we have a complete request yet? */ switch ( httpd_got_request( hc ) ) { case GR_NO_REQUEST: return; case GR_BAD_REQUEST: httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); clear_connection( c, tvP ); return; } /* Yes. Try parsing and resolving it. */ if ( httpd_parse_request( hc ) < 0 ) { clear_connection( c, tvP ); return; } /* Check the throttle table */ if ( ! check_throttles( c ) ) { httpd_send_err( hc, 503, httpd_err503title, "", httpd_err503form, hc->encodedurl ); clear_connection( c, tvP ); return; } /* Start the connection going. */ if ( httpd_start_request( hc, tvP ) < 0 ) { /* Something went wrong. Close down the connection. */ clear_connection( c, tvP ); return; } /* Fill in bytes_to_send. */ if ( hc->got_range ) { c->bytes_sent = hc->init_byte_loc; c->bytes_to_send = hc->end_byte_loc + 1; } else c->bytes_to_send = hc->bytes_to_send; /* Check if it's already handled. */ if ( hc->file_address == (char*) 0 ) { /* No file address means someone else is handling it. */ c->bytes_sent = hc->bytes_sent; clear_connection( c, tvP ); return; } if ( c->bytes_sent >= c->bytes_to_send ) { /* There's nothing to send. */ clear_connection( c, tvP ); return; } /* Cool, we have a valid connection and a file to send to it. */ c->conn_state = CNST_SENDING; c->started_at = tvP->tv_sec; c->wouldblock_delay = 0; client_data.p = c; tmr_cancel( c->idle_read_timer ); c->idle_read_timer = (Timer*) 0; c->idle_send_timer = tmr_create( tvP, idle_send_connection, client_data, IDLE_SEND_TIMELIMIT * 1000L, 0 ); if ( c->idle_send_timer == (Timer*) 0 ) { syslog( LOG_CRIT, "tmr_create(idle_send_connection) failed" ); exit( 1 ); } fdwatch_del_fd( hc->conn_fd ); fdwatch_add_fd( hc->conn_fd, c, FDW_WRITE ); }