diff options
Diffstat (limited to 'nanohttp')
| -rw-r--r-- | nanohttp/nanohttp-server.c | 380 | ||||
| -rw-r--r-- | nanohttp/nanohttp-server.h | 76 | 
2 files changed, 456 insertions, 0 deletions
| diff --git a/nanohttp/nanohttp-server.c b/nanohttp/nanohttp-server.c new file mode 100644 index 0000000..e739267 --- /dev/null +++ b/nanohttp/nanohttp-server.c @@ -0,0 +1,380 @@ +/****************************************************************** + *  $Id: nanohttp-server.c,v 1.1 2004/01/21 12:15:30 snowdrop Exp $ + * + * CSOAP Project:  A http client/server library in C + * Copyright (C) 2003  Ferhat Ayaz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA  02111-1307, USA. + *  + * Email: ayaz@jprogrammer.net + ******************************************************************/ +#include <nanohttp/nanohttp-server.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +typedef struct tag_conndata +{ +  hsocket_t sock; +}conndata_t; + +/* -----------------------------------------------------  + nano httpd internally globals +----------------------------------------------------- */ +static int _httpd_port = 10000; +static hsocket_t _httpd_socket; +static hservice_t *_httpd_services_head = NULL; +static hservice_t *_httpd_services_tail = NULL; + + +/* -----------------------------------------------------  + FUNCTION: httpd_init +----------------------------------------------------- */ +int httpd_init(int argc, char *argv[]) +{ +  int i, status; + +  /* write argument information */ +  log_verbose1("Arguments:");   +  for (i=0;i<argc;i++) +    log_verbose3("argv[%i] = '%s'\n", i, SAVE_STR(argv[i])); + +  /* initialize from arguments */ +  for (i=0;i<argc;i++) { +    if (!strcmp(argv[i], NHTTPD_ARG_PORT) && i < argc-1) { +      _httpd_port = atoi(argv[i+1]); +    } +  } + +  log_debug2("socket bind to port '%d'\n", _httpd_port); + +  /* init built-in services */ +  /* +    httpd_register("/httpd/list", service_list); +  */ + +  /* create socket */ +  hsocket_init(&_httpd_socket); +  status = hsocket_bind(&_httpd_socket, _httpd_port); + +  return status; +} + +/* -----------------------------------------------------  + FUNCTION: httpd_register +----------------------------------------------------- */ + +int httpd_register(const char* ctx,  httpd_service func) +{ +  hservice_t* service; +  log_debug3("register service:t(%p):%s", service, SAVE_STR(ctx)); + +  service = (hservice_t*)malloc(sizeof(hservice_t)); +  service->next = NULL; +  service->func = func; +  strcpy(service->ctx, ctx); +   +  if (_httpd_services_head == NULL) { +    _httpd_services_head = _httpd_services_tail = service; +  } else { +    _httpd_services_tail->next = service; +    _httpd_services_tail = service; +  } + +  return 1; +} + + +/* -----------------------------------------------------  + FUNCTION: httpd_services +----------------------------------------------------- */ +hservice_t *httpd_services() +{ +  return _httpd_services_head; +} + + +/* -----------------------------------------------------  + FUNCTION: httpd_find_service +----------------------------------------------------- */ +static hservice_t *httpd_find_service(const char* ctx)  +{ +  hservice_t *cur = _httpd_services_head; + +  while (cur != NULL) { +    if (!strcmp(cur->ctx, ctx)) { +      return cur; +    } +    cur = cur->next; +  } + +  return NULL; +} + + +/* -----------------------------------------------------  + FUNCTION: httpd_response_set_content_type +----------------------------------------------------- */ +void httpd_response_set_content_type(httpd_conn_t *res,  +				     const char* content_type) +{ +  strncpy(res->content_type, content_type, 25); +} + + +/* -----------------------------------------------------  + FUNCTION: httpd_response_send_header +----------------------------------------------------- */ +int httpd_send_header(httpd_conn_t *res,  +		      int code, const char* text,  +		      hpair_t *pair) +{ +  struct tm stm; +  time_t nw; +  char buffer[255]; +  char header[1024]; +  hpair_t *cur; +  int status; + +  /* set status code */ +  sprintf(header, "HTTP/1.1 %d %s\r\n", code, text); + +  /* set date */ +  nw = time(NULL); +  localtime_r(&nw, &stm); +  strftime(buffer, 255, "Date: %a, %d %b %y %T GMT", &stm); +  strcat(header, buffer); +  strcat(header, "\r\n"); +   +  /* set content-type */ +  if (res->content_type[0] == '\0') { +    strcat(header, "Content-Type: text/html\r\n"); +  } else { +    sprintf(buffer, "Content-Type: %s\r\n", res->content_type); +    strcat(header, buffer); +  } + +  /* set server name */ +  strcat(header, "Server: Nano HTTPD library\r\n"); + +  /* set connection status */ +  strcat(header, "Connection: close\r\n"); + +  /* add pairs */ +  cur = pair; +  while (cur != NULL) { +    sprintf(buffer, "%s: %s\r\n", cur->key, cur->value); +    strcat(header, buffer); +    cur = cur->next; +  } + +  /* set end of header */ +  strcat(header, "\r\n"); + +  /* send header */ +  status = hsocket_nsend(res->sock, header, strlen(header)); +   +  return status; +} + + +int httpd_send_internal_error(httpd_conn_t *conn, const char* errmsg) +{ +  const char *template = +    "<html><body><h3>Error!</h3><hr> Message: '%s' </body></html>\r\n"; + +  char buffer[4064]; +  sprintf(buffer, template, errmsg); +  httpd_send_header(conn, 500, "INTERNAL", NULL); +  return send(conn->sock, buffer, strlen(buffer), 0); +} + +/* -----------------------------------------------------  + FUNCTION: httpd_request_print +----------------------------------------------------- */ +static void httpd_request_print(hrequest_t *req)  +{ +  hpair_t *pair; + +  printf("++++++ Request +++++++++\n"); +  printf(" Method : '%s'\n", req->method); +  printf(" Path   : '%s'\n", req->path); +  printf(" Spec   : '%s'\n", req->spec); +  printf(" Parsed query string :\n"); + +  pair = req->query; +  while (pair != NULL) { +    printf(" %s = '%s'\n", pair->key, pair->value); +    pair = pair->next; +  } +  printf("++++++++++++++++++++++++\n"); +   +} + +/* -----------------------------------------------------  + FUNCTION: httpd_session_main +----------------------------------------------------- */ +static void* httpd_session_main(void *data) +{ +  conndata_t *conn = (conndata_t*)data; +  const char *msg = "SESSION 1.0\n"; +  int len = strlen(msg); +  char buffer[256]; /* temp buffer for recv() */ +  char header[4064]; /* received header */ +  int total; /* result from recv() */ +  int hindex; /* searching end of header */ +  int headerreached =0; /* whether reach header "\n\n" */ +  hrequest_t* req = NULL; /* only for test */ +  httpd_conn_t *rconn; +  hservice_t* service = NULL; + +  header[0] = '\0'; +  len = 0; + + +  log_debug1("starting httpd_session_main()\n"); + +  /*send(conn->sock, msg, len, 0);*/ + +  while (!headerreached) { +    /*printf("receiving ...\n");*/ +    total = recv(conn->sock, buffer, 255, 0); +    if (total==0) break; +    buffer[total]='\0'; +    /*printf("'%s'\n", buffer);*/ + +    /* search end of header */ +     +    for (hindex=0;hindex<total-3;hindex++) { +      if (!strncmp(&buffer[hindex],"\r\n\r\n",4)) { +	break; +      } +    } + +    if (hindex==total-3) { +      hindex = total; +    } else { +      headerreached = 1; +    } + +    len += hindex; +    strncat(header, buffer, hindex); +    header[len]='\0'; +  } + +  printf("=== HEADER ===\n%s\n============\n", header); +  /* call the service */ +  req = hrequest_new_from_buffer(header); +  httpd_request_print(req); +  rconn = (httpd_conn_t*)malloc(sizeof(httpd_conn_t)); +  rconn->sock = conn->sock; +  rconn->content_type[0] = '\0'; + +  service = httpd_find_service(req->path); +  if (service != NULL) { +    log_verbose2("service '%s' found\n", req->path); +    if (service->func != NULL) { +      service->func(rconn, req); +    } else { +      sprintf(buffer,  +	      "service '%s' not registered properly (func == NULL)",  +	      req->path); +      log_verbose1(buffer); +      httpd_send_internal_error(rconn, buffer); +    } +  } else { +    sprintf(buffer, "service '%s' not found", req->path); +      log_verbose1(buffer); +      httpd_send_internal_error(rconn, buffer); +  } + +  close(conn->sock); + +  /*  httpd_response_free(res);*/ +  hrequest_free(req); +   +  pthread_exit(NULL); +}  + + +/* -----------------------------------------------------  + FUNCTION: httpd_run +----------------------------------------------------- */ + +int httpd_run() +{ +  conndata_t *conn; +  pthread_t tid; +  hsocket_t sockfd; +  int err; +  fd_set fds; +  struct timeval timeout; +   +  log_debug1("starting run routine\n"); + +  timeout.tv_sec = 1; +  timeout.tv_usec = 0; + +  /* listen to port */ +  err = hsocket_listen(_httpd_socket,15); +  if (err  != HSOCKET_OK) { +    log_error2("httpd_run(): '%d'\n", err); +    return err; +  } + + +  log_debug2("listening to port '%d'\n", _httpd_port); +   + +  /*  fcntl(_httpd_socket, F_SETFL, O_NONBLOCK);*/ + +  while (1) { +     +    /*FD_ZERO(&fds); +    FD_SET(_httpd_socket, &fds); + +    select(1, &fds, NULL, NULL, &timeout); + +    while ( (FD_ISSET(_httpd_socket, &fds))) +      select(1, &fds, NULL, NULL, &timeout); +    */    +     +   +    if (hsocket_accept(_httpd_socket, &sockfd) != HSOCKET_OK) { +      continue; +    } + + +     conn = (conndata_t*)malloc(sizeof(conndata_t)); +     conn->sock = sockfd; + +     err = pthread_create(&tid, NULL, httpd_session_main, conn);  +     if (err) { +       printf("Error creating thread: ('%d')\n", err); +     } +  } + +  return 0; +} + + diff --git a/nanohttp/nanohttp-server.h b/nanohttp/nanohttp-server.h new file mode 100644 index 0000000..e246f25 --- /dev/null +++ b/nanohttp/nanohttp-server.h @@ -0,0 +1,76 @@ +/****************************************************************** + *  $Id: nanohttp-server.h,v 1.1 2004/01/21 12:15:30 snowdrop Exp $ + * + * CSOAP Project:  A http client/server library in C + * Copyright (C) 2003  Ferhat Ayaz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA  02111-1307, USA. + *  + * Email: ayaz@jprogrammer.net + ******************************************************************/ +#ifndef NANO_HTTP_SERVER_H  +#define NANO_HTTP_SERVER_H  + + +#include <nanohttp/nanohttp-common.h> +#include <nanohttp/nanohttp-socket.h> + + +#define NHTTPD_ARG_PORT "-NHTTPport" + +typedef struct httpd_conn +{ +  hsocket_t sock; +  char content_type[25]; +}httpd_conn_t; + + +/* +  Service callback + */ +typedef void (*httpd_service)(httpd_conn_t*, hrequest_t*); + + +/* + * Service representation object + */ +typedef struct tag_hservice +{ +  char ctx[255]; +  httpd_service func; +  struct tag_hservice *next; +}hservice_t; + + + +/* +  Begin  httpd_* function set + */ +int httpd_init(int argc, char *argv[]); +int httpd_register(const char* ctx,  httpd_service service); +int httpd_run(); +void httpd_destroy(); + +hservice_t *httpd_services(); + +int httpd_send_header(httpd_conn_t *res,  +		      int code, const char* text,  +		      hpair_t *pair); + + + +#endif + | 
