/*--------------------------------------------------
 FUNCTION: httpc_close_free
 DESC: Close and free the given http client object.
 ----------------------------------------------------*/
void
httpc_close_free(httpc_conn_t * conn)
{
  if (conn == NULL)
    return;

  hsocket_close(&(conn->sock));
  httpc_free(conn);

  return;
}
Ejemplo n.º 2
0
static void *
httpd_session_main(void *data)
#endif
{
  struct hrequest_t *req;
  conndata_t *conn;
  httpd_conn_t *rconn;
  hservice_t *service;
  herror_t status;
  struct timeval start, end, duration;
  int done;

  if (gettimeofday(&start, NULL) == -1)
    log_error("gettimeofday failed (%s)", strerror(errno));

  conn = (conndata_t *) data;

  log_verbose("starting new httpd session on socket %d", conn->sock);

  rconn = httpd_new(&(conn->sock));

  done = 0;
  while (!done)
  {
    log_verbose("starting HTTP request on socket %d (%p)", conn->sock, conn->sock.sock);

    if ((status = hrequest_new_from_socket(&(conn->sock), &req)) != H_OK)
    {
      int code;

      switch ((code = herror_code(status)))
      {
        case HSSL_ERROR_SSLCLOSE:
        case HSOCKET_ERROR_RECEIVE:
          log_error("hrequest_new_from_socket failed (%s)", herror_message(status));
          break;
        default:
          httpd_send_bad_request(rconn, herror_message(status));
          break;
      }
      herror_release(status);
      done = 1;
    }
    else
    {
      char *conn_str;

      _httpd_request_print(req);

      conn_str = hpairnode_get_ignore_case(req->header, HEADER_CONNECTION);
      if (conn_str && strncasecmp(conn_str, "close", 6) == 0)
        done = 1;

      if (!done)
        done = req->version == HTTP_1_0 ? 1 : 0;

      if ((service = httpd_find_service(req->path)))
      {
        log_verbose("service '%s' for '%s' found", service->context, req->path);

	if (service->status == NHTTPD_SERVICE_UP)
	{
          pthread_rwlock_wrlock(&(service->statistics->lock));
          service->statistics->requests++;
          pthread_rwlock_unlock(&(service->statistics->lock));

          if (_httpd_authenticate_request(req, service->auth))
          {
            if (service->func != NULL)
            {
              service->func(rconn, req);

              if (gettimeofday(&end, NULL) == -1)
                log_error("gettimeofday failed (%s)", strerror(errno));
              timersub(&end, &start, &duration);

              pthread_rwlock_wrlock(&(service->statistics->lock));
              service->statistics->bytes_received += rconn->sock->bytes_received;
              service->statistics->bytes_transmitted += rconn->sock->bytes_transmitted;
              timeradd(&(service->statistics->time), &duration, &(service->statistics->time));
              pthread_rwlock_unlock(&(service->statistics->lock));

              if (rconn->out && rconn->out->type == HTTP_TRANSFER_CONNECTION_CLOSE)
              {
                log_verbose("Connection close requested");
                done = 1;
              }
            }
            else
            {
              char buffer[256];

              snprintf(buffer, 256, "service '%s' is not registered properly (service function is NULL)", req->path);
              log_verbose("%s", buffer);
              httpd_send_not_implemented(rconn, buffer);
            }
	  }
          else
          {
            httpd_send_unauthorized(rconn, req->path);
            done = 1;
          }
        }
        else
        {
          char buffer[256];

          sprintf(buffer, "service for '%s' is disabled", req->path);
          log_verbose("%s", buffer);
          httpd_send_internal_error(rconn, buffer);
        }
      }
      else
      {
        char buffer[256];
        sprintf(buffer, "no service for '%s' found", req->path);
        log_verbose("%s", buffer);
	httpd_send_not_implemented(rconn, buffer);
        done = 1;
      }
      hrequest_free(req);
    }
  }

  httpd_free(rconn);

  hsocket_close(&(conn->sock));

#ifdef WIN32
  CloseHandle((HANDLE) conn->tid);
#else
  pthread_attr_destroy(&(conn->attr));
#endif

  conn->flag = CONNECTION_FREE;

#ifdef WIN32
  _endthread();
  return 0;
#else
  /* pthread_exits automagically */
  return NULL;
#endif
}
Ejemplo n.º 3
0
herror_t
httpd_run(void)
{
  struct timeval timeout;
  conndata_t *conn;
  herror_t err;
  fd_set fds;

  log_verbose("starting run routine");

  _httpd_register_signal_handler();

  if ((err = hsocket_listen(&_httpd_socket)) != H_OK)
  {
    log_error("hsocket_listen failed (%s)", herror_message(err));
    return err;
  }

  while (_httpd_run)
  {
    conn = _httpd_wait_for_empty_conn();
    if (!_httpd_run)
      break;

    /* Wait for a socket to accept */
    while (_httpd_run)
    {

      /* set struct timeval to the proper timeout */
      timeout.tv_sec = 1;
      timeout.tv_usec = 0;

      /* zero and set file descriptior */
      FD_ZERO(&fds);
      FD_SET(_httpd_socket.sock, &fds);

      /* select socket descriptor */
      switch (select(_httpd_socket.sock + 1, &fds, NULL, NULL, &timeout))
      {
      case 0:
        /* descriptor is not ready */
        continue;
      case -1:
        /* got a signal? */
        continue;
      default:
        /* no nothing */
        break;
      }
      if (FD_ISSET(_httpd_socket.sock, &fds))
      {
        break;
      }
    }

    /* check signal status */
    if (!_httpd_run)
      break;

    if ((err = hsocket_accept(&_httpd_socket, &(conn->sock))) != H_OK)
    {
      log_error("hsocket_accept failed (%s)", herror_message(err));

      hsocket_close(&(conn->sock));

      continue;
    }

    _httpd_start_thread(conn);
  }

  return 0;
}
/*--------------------------------------------------
FUNCTION: httpc_talk_to_server
DESC: This function is the heart of the httpc
module. It will send the request and process the
response.

Here the parameters:

method:
the request method. This can be HTTP_REQUEST_POST and
HTTP_REQUEST_GET.

conn:
the connection object (created with httpc_new())

urlstr:
the complete url in string format.
http://<host>:<port>/<context>
where <port> is not mendatory.

start_cb:
a callback function, which will be called when
the response header is completely arrives.

cb:
a callback function, which will be called everytime
when data arrives.

content_size:
size of content to send.
(only if method is HTTP_REQUEST_POST)

content:
the content data to send.
(only if method is HTTP_REQUEST_POST)

userdata:
a user define data, which will be passed to the
start_cb and cb callbacks as a parameter. This
can also be NULL.


If success, this function will return 0.
>0 otherwise.
----------------------------------------------------*/
static herror_t
httpc_talk_to_server(hreq_method_t method, httpc_conn_t * conn,
                     const char *urlstr)
{

  hurl_t url;
  char buffer[4096];
  herror_t status;
  int ssl;

  if (conn == NULL)
  {
    return herror_new("httpc_talk_to_server",
                      GENERAL_INVALID_PARAM, "httpc_conn_t param is NULL");
  }
  /* Build request header */
  httpc_header_set_date(conn);

  if ((status = hurl_parse(&url, urlstr)) != H_OK)
  {
    log_error2("Can not parse URL '%s'", SAVE_STR(urlstr));
    return status;
  }
/* TODO (#1#): Check for HTTP protocol in URL */

  /* Set hostname */
  httpc_set_header(conn, HEADER_HOST, url.host);

  ssl = url.protocol == PROTOCOL_HTTPS ? 1 : 0;

  /* Open connection */
  if ((status = hsocket_open(&conn->sock, url.host, url.port, ssl)) != H_OK)
    return status;

  switch(method)
  {
    case HTTP_REQUEST_GET:

      sprintf(buffer, "GET %s HTTP/%s\r\n",
        (url.context[0] != '\0') ? url.context : ("/"),
        (conn->version == HTTP_1_0) ? "1.0" : "1.1");
      break;

    case HTTP_REQUEST_POST:

      sprintf(buffer, "POST %s HTTP/%s\r\n",
        (url.context[0] != '\0') ? url.context : ("/"),
        (conn->version == HTTP_1_0) ? "1.0" : "1.1");
      break;

    default:
      log_error1("Unknown method type!");
      return herror_new("httpc_talk_to_server",
        GENERAL_INVALID_PARAM,
        "hreq_method_t must be  HTTP_REQUEST_GET or HTTP_REQUEST_POST");
  }

  log_verbose1("Sending request...");
  if ((status = hsocket_send(&(conn->sock), buffer)) != H_OK)
  {
    log_error2("Cannot send request (%s)", herror_message(status));
    hsocket_close(&(conn->sock));
    return status;
  }

  log_verbose1("Sending header...");
  if ((status = httpc_send_header(conn)) != H_OK)
  {
    log_error2("Cannot send header (%s)", herror_message(status));
    hsocket_close(&(conn->sock));
    return status;
  }

  return H_OK;
}