summaryrefslogtreecommitdiffstats
path: root/nanohttp/nanohttp-server.c
diff options
context:
space:
mode:
Diffstat (limited to 'nanohttp/nanohttp-server.c')
-rw-r--r--nanohttp/nanohttp-server.c680
1 files changed, 354 insertions, 326 deletions
diff --git a/nanohttp/nanohttp-server.c b/nanohttp/nanohttp-server.c
index a752fda..ef7c503 100644
--- a/nanohttp/nanohttp-server.c
+++ b/nanohttp/nanohttp-server.c
@@ -1,28 +1,34 @@
/******************************************************************
- * $Id: nanohttp-server.c,v 1.7 2004/05/18 16:37:21 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
- ******************************************************************/
+* $Id: nanohttp-server.c,v 1.8 2004/08/26 17:07:47 rans 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 WIN32
+#include "wsockcompat.h"
+#include <winsock2.h>
+#define close(s) closesocket(s)
+#endif
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -34,24 +40,25 @@
#include <string.h>
#include <signal.h>
+#ifndef WIN32
/* According to POSIX 1003.1-2001 */
#include <sys/select.h>
-
+
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
-
+#endif
typedef struct tag_conndata
{
- hsocket_t sock;
+ hsocket_t sock;
}conndata_t;
/* -----------------------------------------------------
- nano httpd internally globals
+nano httpd internally globals
----------------------------------------------------- */
static int _httpd_port = 10000;
static hsocket_t _httpd_socket;
@@ -61,347 +68,368 @@ static int _httpd_run = 1;
static int _httpd_terminate_signal = SIGTERM;
/* -----------------------------------------------------
- FUNCTION: httpd_init
+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'", 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]);
- } else if (!strcmp(argv[i], NHTTPD_ARG_TERMSIG) && i < argc-1) {
- _httpd_terminate_signal = atoi(argv[i+1]);
- }
- }
-
- log_verbose2("socket bind to port '%d'", _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;
+ int i, status;
+
+ /* write argument information */
+ log_verbose1("Arguments:");
+ for (i=0;i<argc;i++)
+ log_verbose3("argv[%i] = '%s'", 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]);
+ } else if (!strcmp(argv[i], NHTTPD_ARG_TERMSIG) && i < argc-1) {
+ _httpd_terminate_signal = atoi(argv[i+1]);
+ }
+ }
+
+ log_verbose2("socket bind to port '%d'", _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
+FUNCTION: httpd_register
----------------------------------------------------- */
int httpd_register(const char* ctx, httpd_service func)
{
- hservice_t* service;
- log_verbose3("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;
+ hservice_t* service;
+ log_verbose3("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
+FUNCTION: httpd_services
----------------------------------------------------- */
hservice_t *httpd_services()
{
- return _httpd_services_head;
+ return _httpd_services_head;
}
/* -----------------------------------------------------
- FUNCTION: httpd_find_service
+FUNCTION: httpd_find_service
----------------------------------------------------- */
static hservice_t *httpd_find_service(const char* ctx)
{
- hservice_t *cur = _httpd_services_head;
+ hservice_t *cur = _httpd_services_head;
- while (cur != NULL) {
- if (!strcmp(cur->ctx, ctx)) {
- return cur;
- }
- cur = cur->next;
- }
+ while (cur != NULL) {
+ if (!strcmp(cur->ctx, ctx)) {
+ return cur;
+ }
+ cur = cur->next;
+ }
- return NULL;
+ return NULL;
}
/* -----------------------------------------------------
- FUNCTION: httpd_response_set_content_type
+FUNCTION: httpd_response_set_content_type
----------------------------------------------------- */
void httpd_response_set_content_type(httpd_conn_t *res,
- const char* content_type)
+ const char* content_type)
{
- strncpy(res->content_type, content_type, 25);
+ strncpy(res->content_type, content_type, 25);
}
/* -----------------------------------------------------
- FUNCTION: httpd_response_send_header
+FUNCTION: httpd_response_send_header
----------------------------------------------------- */
int httpd_send_header(httpd_conn_t *res,
- int code, const char* text,
- hpair_t *pair)
+ 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;
+ 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";
+ const char *template1 =
+ "<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);
+ char buffer[4064];
+ sprintf(buffer, template1, errmsg);
+ httpd_send_header(conn, 500, "INTERNAL", NULL);
+ return send(conn->sock, buffer, strlen(buffer), 0);
}
/* -----------------------------------------------------
- FUNCTION: httpd_request_print
+FUNCTION: httpd_request_print
----------------------------------------------------- */
static void httpd_request_print(hrequest_t *req)
{
- hpair_t *pair;
-
- log_verbose1("++++++ Request +++++++++");
- log_verbose2(" Method : '%s'", req->method);
- log_verbose2(" Path : '%s'", req->path);
- log_verbose2(" Spec : '%s'", req->spec);
- log_verbose1(" Parsed query string :");
-
- pair = req->query;
- while (pair != NULL) {
- log_verbose3(" %s = '%s'", pair->key, pair->value);
- pair = pair->next;
- }
- log_verbose1("++++++++++++++++++++++++");
-
+ hpair_t *pair;
+
+ log_verbose1("++++++ Request +++++++++");
+ log_verbose2(" Method : '%s'", req->method);
+ log_verbose2(" Path : '%s'", req->path);
+ log_verbose2(" Spec : '%s'", req->spec);
+ log_verbose1(" Parsed query string :");
+
+ pair = req->query;
+ while (pair != NULL) {
+ log_verbose3(" %s = '%s'", pair->key, pair->value);
+ pair = pair->next;
+ }
+ log_verbose1("++++++++++++++++++++++++");
+
}
/* -----------------------------------------------------
- FUNCTION: httpd_session_main
+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 ch[2];
- 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;
- char *content_length_str;
- long content_length = 0;
-
- header[0] = '\0';
- len = 0;
-
-
- log_verbose1("starting httpd_session_main()");
-
- while (len < 4064) {
- /*printf("receiving ...\n");*/
- total = recv(conn->sock, ch, 1, 0);
- if (total==0) break;
- header[len] = ch[0];
- len++;
- if (len > 3) {
- if (!strncmp(&header[len-4], "\r\n\r\n", 4)) {
- header[len] = '\0';
- break;
- }
- }
- }
-
- /* log_verbose2("=== 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", 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);
+ conndata_t *conn = (conndata_t*)data;
+ const char *msg = "SESSION 1.0\n";
+ int len = strlen(msg);
+ char ch[2];
+ 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;
+ char *content_length_str;
+ long content_length = 0;
+
+ header[0] = '\0';
+ len = 0;
+
+
+ log_verbose1("starting httpd_session_main()");
+
+ while (len < 4064) {
+ /*printf("receiving ...\n");*/
+ total = recv(conn->sock, ch, 1, 0);
+ if (total==0) break;
+ header[len] = ch[0];
+ len++;
+ if (len > 3) {
+ if (!strncmp(&header[len-4], "\r\n\r\n", 4)) {
+ header[len] = '\0';
+ break;
+ }
+ }
+ }
+
+ /* log_verbose2("=== 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", 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);
+ return service;
}
/* -----------------------------------------------------
- FUNCTION: httpd_term
+FUNCTION: httpd_term
----------------------------------------------------- */
void httpd_term(int sig)
{
- if (sig == _httpd_terminate_signal)
- _httpd_run = 0;
+ if (sig == _httpd_terminate_signal)
+ _httpd_run = 0;
}
/* -----------------------------------------------------
- FUNCTION: httpd_run
+FUNCTION: httpd_run
----------------------------------------------------- */
int httpd_run()
{
- conndata_t *conn;
- pthread_t tid;
- pthread_attr_t attr;
- hsocket_t sockfd;
- int err;
- fd_set fds;
- struct timeval timeout;
-
- pthread_attr_init(&attr);
+ conndata_t *conn;
+ pthread_t tid;
+ pthread_attr_t attr;
+ hsocket_t sockfd;
+ int err;
+ fd_set fds;
+ struct timeval timeout;
+
+ pthread_attr_init(&attr);
#ifdef PTHREAD_CREATE_DETACHED
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
#endif
-
- log_verbose1("starting run routine");
- 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'", err);
- return err;
- }
+ log_verbose1("starting run routine");
+ 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'", err);
+ return err;
+ }
- log_verbose2("registering termination signal handler (SIGNAL:%d)", _httpd_terminate_signal);
- signal(_httpd_terminate_signal, httpd_term);
+ log_verbose2("registering termination signal handler (SIGNAL:%d)", _httpd_terminate_signal);
+ signal(_httpd_terminate_signal, httpd_term);
+ log_verbose2("listening to port '%d'", _httpd_port);
- log_verbose2("listening to port '%d'", _httpd_port);
-
- fcntl(_httpd_socket, F_SETFL, O_NONBLOCK);
+#ifndef WIN32
+#if HSOCKET_BLOCKMODE!=0
+ fcntl(_httpd_socket, F_SETFL, O_NONBLOCK);
+#endif
+#else
+ unsigned long iMode=HSOCKET_BLOCKMODE;
+ if(ioctlsocket(_httpd_socket, FIONBIO, (u_long FAR*) &iMode) == INVALID_SOCKET)
+ {
+ log_error1("ioctlsocket error");
+ return -1;
+ }
+#endif
- while (_httpd_run) {
-
- FD_ZERO(&fds);
- FD_SET(_httpd_socket, &fds);
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
- {
- timeout.tv_sec = 1;
- timeout.tv_usec = 0;
- select(1, &fds, NULL, NULL, &timeout);
- } while (_httpd_run && (FD_ISSET(_httpd_socket, &fds)))
+ while (_httpd_run) {
+
+ FD_ZERO(&fds);
+ FD_SET(_httpd_socket, &fds);
+
+#ifndef WIN32
+ select(1, &fds, NULL, NULL, &timeout);
+#else
+ if(select(1, &fds, NULL, NULL, &timeout)==SOCKET_ERROR)
+ {
+ err=WSAGetLastError();
+ log_error1("select error");
+ return -1;
+ }
+#endif
- if (!_httpd_run)
- break;
-
- if (hsocket_accept(_httpd_socket, &sockfd) != HSOCKET_OK) {
- continue;
- }
+ while (_httpd_run && (FD_ISSET(_httpd_socket, &fds)))
+ if (!_httpd_run)
+ break;
- conn = (conndata_t*)malloc(sizeof(conndata_t));
- conn->sock = sockfd;
+ if (hsocket_accept(_httpd_socket, &sockfd) != HSOCKET_OK) {
+ continue;
+ }
- err = pthread_create(&tid, &attr, httpd_session_main, conn);
- if (err) {
- log_error2("Error creating thread: ('%d')", err);
- }
- }
- return 0;
+ conn = (conndata_t*)malloc(sizeof(conndata_t));
+ conn->sock = sockfd;
+
+ err = pthread_create(&tid, &attr, httpd_session_main, conn);
+ if (err) {
+ log_error2("Error creating thread: ('%d')", err);
+ }
+ }
+
+ return 0;
}
@@ -409,49 +437,49 @@ int httpd_run()
char *httpd_get_postdata(httpd_conn_t *conn, hrequest_t *req, long *received, long max)
{
- char *content_length_str;
- long content_length = 0;
- long total = 0;
- char *postdata = NULL;
-
- if (!strcmp(req->method, "POST")) {
-
- content_length_str =
- hpairnode_get_ignore_case(req->header, HEADER_CONTENT_LENGTH);
-
- if (content_length_str != NULL)
- content_length = atol(content_length_str);
-
- } else {
- log_warn1("Not a POST method");
- return NULL;
- }
-
- if (content_length > max && max != -1)
- return NULL;
-
- if (content_length == 0) {
- *received = 0;
- postdata = (char*)malloc(1);
- postdata[0] = '\0';
- return postdata;
- }
-
- postdata = (char*)malloc(content_length+1);
- if (postdata == NULL) {
- log_error1("Not enough memory");
- return NULL;
- }
-
-
- if (hsocket_read(conn->sock, postdata,
- (int)content_length, 1) == HSOCKET_OK) {
- *received = content_length;
- postdata[content_length] = '\0';
- return postdata;
- }
-
- free (postdata);
- return NULL;
-
+ char *content_length_str;
+ long content_length = 0;
+ long total = 0;
+ char *postdata = NULL;
+
+ if (!strcmp(req->method, "POST")) {
+
+ content_length_str =
+ hpairnode_get_ignore_case(req->header, HEADER_CONTENT_LENGTH);
+
+ if (content_length_str != NULL)
+ content_length = atol(content_length_str);
+
+ } else {
+ log_warn1("Not a POST method");
+ return NULL;
+ }
+
+ if (content_length > max && max != -1)
+ return NULL;
+
+ if (content_length == 0) {
+ *received = 0;
+ postdata = (char*)malloc(1);
+ postdata[0] = '\0';
+ return postdata;
+ }
+
+ postdata = (char*)malloc(content_length+1);
+ if (postdata == NULL) {
+ log_error1("Not enough memory");
+ return NULL;
+ }
+
+
+ if (hsocket_read(conn->sock, postdata,
+ (int)content_length, 1) == HSOCKET_OK) {
+ *received = content_length;
+ postdata[content_length] = '\0';
+ return postdata;
+ }
+
+ free (postdata);
+ return NULL;
+
}