Exemplo n.º 1
0
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;
}
Exemplo n.º 3
0
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 );
    }