diff options
author | snowdrop | 2003-12-11 14:51:04 +0000 |
---|---|---|
committer | snowdrop | 2003-12-11 14:51:04 +0000 |
commit | 78e32265532d383c451e34afe46f1139827fb43f (patch) | |
tree | 283be970d3c982bcd5095ac0c93e9aa53b22eba0 | |
parent | f8471ea21faa7a820855a261ae094e588886b73d (diff) | |
download | csoap-78e32265532d383c451e34afe46f1139827fb43f.tar.gz csoap-78e32265532d383c451e34afe46f1139827fb43f.tar.bz2 |
initial import
-rw-r--r-- | examples/nanohttp/Makefile.am | 15 | ||||
-rw-r--r-- | examples/nanohttp/httpget.c | 75 | ||||
-rw-r--r-- | examples/nanohttp/httpgetcb.c | 88 | ||||
-rw-r--r-- | nanohttp/Makefile.am | 29 | ||||
-rw-r--r-- | nanohttp/nanohttp-client.c | 494 | ||||
-rw-r--r-- | nanohttp/nanohttp-client.h | 88 | ||||
-rw-r--r-- | nanohttp/nanohttp-common.c | 357 | ||||
-rw-r--r-- | nanohttp/nanohttp-common.h | 142 | ||||
-rw-r--r-- | nanohttp/nanohttp-socket.c | 324 | ||||
-rw-r--r-- | nanohttp/nanohttp-socket.h | 138 | ||||
-rw-r--r-- | nanohttp/readme.txt | 2 |
11 files changed, 1752 insertions, 0 deletions
diff --git a/examples/nanohttp/Makefile.am b/examples/nanohttp/Makefile.am new file mode 100644 index 0000000..e5cda5c --- /dev/null +++ b/examples/nanohttp/Makefile.am @@ -0,0 +1,15 @@ +bin_PROGRAMS=httpget httpgetcb + +httpget_SOURCES=httpget.c +INCLUDES=-I$(top_srcdir)/ $(LIBXML_CFLAGS) +httpget_LDFLAGS=-L$(top_builddir)/nanohttp -lnanohttp-$(GENERIC_API_VERSION) \ +$(LIBXML_LIBS) + +httpgetcb_SOURCES=httpgetcb.c +INCLUDES=-I$(top_srcdir)/ $(LIBXML_CFLAGS) +httpgetcb_LDFLAGS=-L$(top_builddir)/nanohttp -lnanohttp-$(GENERIC_API_VERSION) \ +$(LIBXML_LIBS) + + + + diff --git a/examples/nanohttp/httpget.c b/examples/nanohttp/httpget.c new file mode 100644 index 0000000..3ace8c2 --- /dev/null +++ b/examples/nanohttp/httpget.c @@ -0,0 +1,75 @@ +/****************************************************************** + * $Id: httpget.c,v 1.1 2003/12/11 14:52:14 snowdrop Exp $ + * + * CSOAP Project: A http client/server library in C (example) + * 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-client.h> + +#include <stdio.h> + + +int main(int argc, char *argv[]) +{ + httpc_conn_t *conn; + hresponse_t *res; + hpair_t *pair; + + if (argc < 2) { + fprintf(stderr, "usage %s <url>\n", argv[0]); + exit(1); + } + + conn = httpc_new(); + res = httpc_get(conn, argv[1]); + + if (res != NULL) { + log_info2("Spec : '%s'", res->spec); + log_info2("Status: %d", res->errcode); + log_info2("Desc : '%s'", res->desc); + + if (res->body) { + pair = res->header; + while (pair != NULL) { + log_debug3("%s: %s", pair->key, pair->value); + pair = pair->next; + } + + puts(res->body); + } + else + log_error1("body is null"); + + hresponse_free(res); + } else { + log_error1("response object is null"); + } + + httpc_free(conn); + return 0; +} + + + + + + + + diff --git a/examples/nanohttp/httpgetcb.c b/examples/nanohttp/httpgetcb.c new file mode 100644 index 0000000..1f2ca8f --- /dev/null +++ b/examples/nanohttp/httpgetcb.c @@ -0,0 +1,88 @@ +/****************************************************************** + * $Id: httpgetcb.c,v 1.1 2003/12/11 14:52:14 snowdrop Exp $ + * + * CSOAP Project: A http client/server library in C (example) + * 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-client.h> + +#include <stdio.h> + +FILE *fd; + +void my_start_callback(httpc_conn_t *conn, void *userdata, + hpair_t *header, const char *spec, + int errcode, const char *desc) +{ + hpair_t *pair; + + log_debug2("Spec : '%s'", spec); + log_debug2("Status: %d", errcode); + log_debug2("Desc : '%s'", desc); + + pair = header; + while (pair != NULL) { + log_debug3("%s: %s", pair->key, pair->value); + pair = pair->next; + } + + log_debug1("\n"); +} + +void my_callback(int counter, httpc_conn_t* conn, + void *userdata, int size, char *buffer) +{ + /* print body */ + if (size > 0) fwrite(buffer, size, 1, fd); +} + + +int main(int argc, char *argv[]) +{ + httpc_conn_t *conn; + + if (argc < 3) { + fprintf(stderr, "usage %s <url> <filename>\n", argv[0]); + exit(1); + } + + fd = fopen(argv[2], "w"); + if (fd == NULL) { + fprintf(stderr, "can not open '%s'\n", argv[2]); + exit(1); + } + + conn = httpc_new(); + httpc_get_cb(conn, argv[1], my_start_callback, my_callback, NULL); + httpc_free(conn); + + fclose(fd); + + log_debug1("finished"); + + return 0; +} + + + + + + + diff --git a/nanohttp/Makefile.am b/nanohttp/Makefile.am new file mode 100644 index 0000000..c290ff6 --- /dev/null +++ b/nanohttp/Makefile.am @@ -0,0 +1,29 @@ +## Source directory + + +h_sources = nanohttp-common.h\ +nanohttp-client.h\ +nanohttp-socket.h + +cc_sources = nanohttp-common.c\ +nanohttp-client.c\ +nanohttp-socket.c + +library_includedir=$(includedir)/$(NANOHTTP_LIBRARY_NAME)-$(NANOHTTP_API_VERSION)/$(NANOHTTP_LIBRARY_NAME) +library_include_HEADERS = $(h_sources) + +INCLUDES = -I$(top_srcdir) + +# GENERIC_API_VERSION is 1.0 +lib_LTLIBRARIES= libnanohttp-1.0.la +libnanohttp_1_0_la_SOURCES= $(h_sources) $(cc_sources) +libnanohttp_1_0_la_LDFLAGS= -version-info $(NANOHTTP_LIBRARY_VERSION) -release $(NANOHTTP_RELEASE) + + + + + + + + + diff --git a/nanohttp/nanohttp-client.c b/nanohttp/nanohttp-client.c new file mode 100644 index 0000000..72af32e --- /dev/null +++ b/nanohttp/nanohttp-client.c @@ -0,0 +1,494 @@ +/****************************************************************** + * $Id: nanohttp-client.c,v 1.1 2003/12/11 14:51:04 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-client.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <time.h> + +#include <stdio.h> +#include <stdlib.h> + + +/*-------------------------------------------------- + STRUCTURES +----------------------------------------------------*/ +typedef struct httpc_cb_userdata +{ + httpc_conn_t *conn; + void *userdata; + httpc_response_callback callback; + int counter; +}httpc_cb_userdata_t; + + +/*-------------------------------------------------- + FUNCTION: httpc_new +----------------------------------------------------*/ +httpc_conn_t* httpc_new() +{ + httpc_conn_t* res = (httpc_conn_t*)malloc(sizeof(httpc_conn_t)); + + hsocket_init(&res->sock); + res->header = NULL; + res->url = NULL; + + return res; +} + + +/*-------------------------------------------------- + FUNCTION: httpc_free +----------------------------------------------------*/ +void httpc_free(httpc_conn_t* conn) +{ + const char *FUNC = "httpc_free"; + hpair_t *tmp; + + if (conn != NULL) { + hsocket_free(conn->sock); + + + + while (conn->header != NULL) { + tmp = conn->header; + conn->header = conn->header->next; + hpairnode_free(tmp); + } + + free(conn); + } +} + + +/*-------------------------------------------------- + FUNCTION: httpc_add_header +----------------------------------------------------*/ +void httpc_add_header(httpc_conn_t *conn, const char* key, const char* value) +{ + const char *FUNC = "httpc_add_header"; + + if (conn == NULL) { + log_warn(FUNC, "Connection object is NULL"); + return; + } + + conn->header = hpairnode_new(key, value, conn->header); +} + + +/*-------------------------------------------------- + FUNCTION: httpc_set_header +----------------------------------------------------*/ +int httpc_set_header(httpc_conn_t *conn, const char* key, const char* value) +{ + const char *FUNC = "httpc_set_header"; + hpair_t *p; + + if (conn == NULL) { + log_warn(FUNC, "Connection object is NULL"); + return 0; + } + + p = conn->header; + while (p != NULL) { + if (p->key != NULL) { + if (!strcmp(p->key, key)) { + free(p->value); + p->value = (char*)malloc(strlen(value)+1); + strcpy(p->value, value); + return 1; + } + } + p = p->next; + } + + conn->header = hpairnode_new(key, value, conn->header); + return 0; +} + + + +/*-------------------------------------------------- + FUNCTION: httpc_build_header +----------------------------------------------------*/ +static +void httpc_build_header(httpc_conn_t *conn) +{ + char buffer[255]; + time_t nw; + struct tm stm; + + /* Set date */ + nw = time(NULL); + localtime_r(&nw, &stm); + strftime(buffer, 255, "%a, %d %b %y %T GMT", &stm); + httpc_set_header(conn, HEADER_DATE, buffer); + +} + +/*-------------------------------------------------- + FUNCTION: httpc_get +----------------------------------------------------*/ +hresponse_t *httpc_get(httpc_conn_t *conn, const char* urlstr) +{ + const char *FUNC = "httpc_get"; + + hurl_t *url; + char buffer[255]; + int status; + char *response; + int rsize; + hresponse_t *res; + char *rest; + int restsize; + + if (conn == NULL) { + log_error(FUNC, "Connection object is NULL"); + return NULL; + } + + /* set response to 0 to allocate + it in hsocket_recv */ + response = 0; + + /* Build request header */ + httpc_build_header(conn); + + /* Create url */ + url = hurl_new(urlstr); + if (url == NULL) { + log_error(FUNC, "Can not parse URL '%s'", SAVE_STR(urlstr)); + return NULL; + } + + /* Set hostname */ + httpc_set_header(conn, HEADER_HOST, url->host); + + /* Open connection */ + status = hsocket_open(&conn->sock, url->host, url->port); + if (status != HSOCKET_OK) { + log_error(FUNC, "Can not open connection to '%s' (status:%d)", + SAVE_STR(url->host), status); + return NULL; + } + + /* Send GET */ + sprintf(buffer, "GET %s HTTP/1.1\r\n", + (url->context)?url->context:("/")); + status = hsocket_send(conn->sock, buffer); + if (status != HSOCKET_OK) { + log_error(FUNC, "Can not send GET (status:%d)", status); + hsocket_close(conn->sock); + return NULL; + } + + /* Send Header */ + status = httpc_send_header(conn); + if (status != HSOCKET_OK) { + log_error(FUNC, "Can not send header (status:%d)", status); + hsocket_close(conn->sock); + return NULL; + } + + /* Receive Response */ + status = hsocket_recv(conn->sock, &response, &rsize); + if (status != HSOCKET_OK) { + log_error(FUNC, "Can not receive response (status:%d)", status); + return NULL; + } + + + /*status = hsocket_recv_limit(conn->sock, &response, + "\r\n\r\n", &rest, &rsize, &restsize); + if (status != HSOCKET_OK) { + log_error(FUNC, "Can not receive response (status:%d)", status); + return NULL; + } + */ + res = hresponse_new(response); + + if (res == NULL) { + free(response); + return NULL; + } + + /*res->body = rest;*/ + return res; +} + + +/*-------------------------------------------------- + FUNCTION: httpc_send_header +----------------------------------------------------*/ +int httpc_send_header(httpc_conn_t *conn) +{ + hpair_t *p; + int status; + char buffer[1024]; + + p = conn->header; + while (p != NULL) { + if (p->key && p->value) { + sprintf(buffer, "%s: %s\r\n", p->key, p->value); + status = hsocket_send(conn->sock, buffer); + if (status != HSOCKET_OK) + return status; + } + p = p->next; + } + + status = hsocket_send(conn->sock, "\r\n"); + return status; +} + +/*-------------------------------------------------- + FUNCTION: httpc_post +----------------------------------------------------*/ +hresponse_t *httpc_post(httpc_conn_t *conn, const char *urlstr, const char *content) +{ + const char *FUNC = "httpc_post"; + int content_length; + hurl_t *url; + char buffer[255]; + int status; + char *response; + hresponse_t *res; + int rsize; + + if (conn == NULL) { + log_error(FUNC, "Connection object is NULL"); + return NULL; + } + + if (content == NULL) { + log_error(FUNC, "Content is NULL"); + return NULL; + } + + /* set response to 0 to allocate + it in hsocket_recv */ + response = 0; + + /* Build request header */ + httpc_build_header(conn); + + /* Create url */ + url = hurl_new(urlstr); + if (url == NULL) { + log_error(FUNC, "Can not parse URL '%s'", SAVE_STR(urlstr)); + return NULL; + } + + /* Set content length */ + content_length = strlen(content); + sprintf(buffer, "%d", content_length); + httpc_set_header(conn, HEADER_CONTENT_LENGTH, buffer); + + /* Set hostname */ + httpc_set_header(conn, HEADER_HOST, url->host); + + /* Open connection */ + status = hsocket_open(&conn->sock, url->host, url->port); + if (status != HSOCKET_OK) { + log_error(FUNC, "Can not open connection to '%s' (status:%d)", + SAVE_STR(url->host), status); + return NULL; + } + + /* Send POST */ + sprintf(buffer, "POST %s HTTP/1.1\r\n", + (url->context)?url->context:("/")); + status = hsocket_send(conn->sock, buffer); + if (status != HSOCKET_OK) { + log_error(FUNC, "Can not send POST (status:%d)", status); + hsocket_close(conn->sock); + return NULL; + } + + /* Send Header */ + status = httpc_send_header(conn); + if (status != HSOCKET_OK) { + log_error(FUNC, "Can not send header (status:%d)", status); + hsocket_close(conn->sock); + return NULL; + } + + /* Send Content */ + status = hsocket_send(conn->sock, content); + if (status != HSOCKET_OK) { + log_error(FUNC, "Can not send content (status:%d)", status); + return NULL; + } + + /* Receive Response */ + status = hsocket_recv(conn->sock, &response, &rsize); + if (status != HSOCKET_OK) { + log_error(FUNC, "Can not receive response (status:%d)", status); + return NULL; + } + + res = hresponse_new(response); + if (res == NULL) { + free(response); + return NULL; + } + + return res; +} + + +/*-------------------------------------------------- + FUNCTION: httpc_recv_cb_callback +----------------------------------------------------*/ +int httpc_recv_cb_callback(hsocket_t sock, char *buffer, + int size, void *userdata) +{ + httpc_cb_userdata_t *cbdata = (httpc_cb_userdata_t*)userdata; + + cbdata->callback(cbdata->counter++, cbdata->conn, + cbdata->userdata, size, buffer); + return 1; +} + + +/*-------------------------------------------------- + FUNCTION: httpc_get_cb +----------------------------------------------------*/ +int httpc_get_cb(httpc_conn_t *conn, const char *urlstr, + httpc_response_start_callback start_cb, + httpc_response_callback cb, void *userdata) +{ + hurl_t *url; + char buffer[255]; + int status; + char *response; + int rsize; + hresponse_t *res; + char *rest; + int restsize; + httpc_cb_userdata_t cbdata; + + if (conn == NULL) { + log_error1("Connection object is NULL"); + return 1; + } + + /* set response to 0 to allocate + it in hsocket_recv */ + response = 0; + + /* Build request header */ + httpc_build_header(conn); + + /* Create url */ + url = hurl_new(urlstr); + if (url == NULL) { + log_error2("Can not parse URL '%s'", SAVE_STR(urlstr)); + return 2; + } + + /* Set hostname */ + httpc_set_header(conn, HEADER_HOST, url->host); + + /* Open connection */ + status = hsocket_open(&conn->sock, url->host, url->port); + if (status != HSOCKET_OK) { + log_error3("Can not open connection to '%s' (status:%d)", + SAVE_STR(url->host), status); + return 3; + } + + /* Send GET */ + sprintf(buffer, "GET %s HTTP/1.1\r\n", + (url->context)?url->context:("/")); + status = hsocket_send(conn->sock, buffer); + if (status != HSOCKET_OK) { + log_error2("Can not send GET (status:%d)", status); + hsocket_close(conn->sock); + return 4; + } + + /* Send Header */ + status = httpc_send_header(conn); + if (status != HSOCKET_OK) { + log_error2("Can not send header (status:%d)", status); + hsocket_close(conn->sock); + return 5; + } + + /* Receive Response */ + + status = hsocket_recv_limit(conn->sock, &response, + "\r\n\r\n", &rest, &rsize, &restsize); + if (status != HSOCKET_OK) { + log_error2("Can not receive response (status:%d)", status); + return NULL; + } + + res = hresponse_new(response); + if (res == NULL) { + log_error2("Can't create response (url:'%s')", urlstr); + return 6; + } + + /* Invoke callback */ + start_cb(conn, userdata, res->header, res->spec, res->errcode, res->desc); + + /* Invoke callback for rest */ + cb(0, conn, userdata, restsize, rest); + + /* rest and response are no longer required */ + free(rest); + free(response); + + /* Invoke with callback */ + cbdata.conn = conn; + cbdata.userdata = userdata; + cbdata.callback = cb; + cbdata.counter = 1; + + hsocket_recv_cb(conn->sock, httpc_recv_cb_callback, &cbdata); + + return 0; +} + + +/*-------------------------------------------------- + FUNCTION: httpc_post_cb +----------------------------------------------------*/ +int httpc_post_cb(httpc_conn_t *conn, const char *url, + httpc_response_start_callback start_cb, + httpc_response_callback cb, void *userdata) +{ + return 1; +} + + + + + + diff --git a/nanohttp/nanohttp-client.h b/nanohttp/nanohttp-client.h new file mode 100644 index 0000000..60abc57 --- /dev/null +++ b/nanohttp/nanohttp-client.h @@ -0,0 +1,88 @@ +/****************************************************************** + * $Id: nanohttp-client.h,v 1.1 2003/12/11 14:51:04 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_CLIENT_H +#define NANO_HTTP_CLIENT_H + + +#include <nanohttp/nanohttp-common.h> +#include <nanohttp/nanohttp-socket.h> + + +typedef struct httpc_conn +{ + hsocket_t sock; + hpair_t *header; + hurl_t *url; +}httpc_conn_t; + +/* + PROTOTYPE: + void my_callback(int counter, httpc_conn_t* conn, + void *userdata, int size, char *buffer) + */ +typedef void (*httpc_response_callback)(int, httpc_conn_t*, void*,int,char*); + +/* + void my_start_callback(httpc_conn_t *conn, void *userdata, + hpair_t *header, const char *spec, + int errcode, const char *desc) + */ +typedef void (*httpc_response_start_callback)(httpc_conn_t*, void*, hpair_t*, + const char*, int, const char*); + +httpc_conn_t* httpc_new(); +void httpc_free(httpc_conn_t* conn); + +void httpc_add_header(httpc_conn_t *conn, const char* key, const char* value); +int httpc_set_header(httpc_conn_t *conn, const char* key, const char* value); + +hresponse_t *httpc_get(httpc_conn_t *conn, const char *url); +hresponse_t *httpc_post(httpc_conn_t *conn, const char *url, const char *content); + +int httpc_get_cb(httpc_conn_t *conn, const char *url, + httpc_response_start_callback start_cb, + httpc_response_callback cb, void *userdata); + +int httpc_post_cb(httpc_conn_t *conn, const char *url, + httpc_response_start_callback start_cb, + httpc_response_callback cb, void *userdata); + + +#endif + + + + + + + + + + + + + + + + diff --git a/nanohttp/nanohttp-common.c b/nanohttp/nanohttp-common.c new file mode 100644 index 0000000..9efe0ac --- /dev/null +++ b/nanohttp/nanohttp-common.c @@ -0,0 +1,357 @@ +/****************************************************************** + * $Id: nanohttp-common.c,v 1.1 2003/12/11 14:51:04 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-common.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> + + +static log_level_t loglevel = HLOG_DEBUG; + +log_level_t log_set_level(log_level_t level) +{ + log_level_t old = loglevel; + loglevel = level; + return old; +} + + +log_level_t log_get_level() +{ + return loglevel; +} + + +static +void log_write(log_level_t level, const char *prefix, + const char* func, const char *format, va_list ap) +{ + char buffer[1054]; + char buffer2[1054]; + + if (level < loglevel) return; + + sprintf(buffer, "*%s*: [%s] %s\n", prefix, func, format); + vsprintf(buffer2, buffer, ap); + printf(buffer2); + fflush(stdout); +} + +void log_debug(const char* FUNC, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + log_write(HLOG_DEBUG, "DEBUG", FUNC, format, ap); + va_end(ap); +} + +void log_info(const char* FUNC, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + log_write(HLOG_INFO, "INFO", FUNC, format, ap); + va_end(ap); +} + +void log_warn(const char* FUNC, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + log_write(HLOG_WARN, "WARN", FUNC, format, ap); + va_end(ap); +} + +void log_error(const char* FUNC, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + log_write(HLOG_ERROR, "ERROR", FUNC, format, ap); + va_end(ap); +} + + +hpair_t *hpairnode_new(const char* key, const char* value, hpair_t *next) +{ + hpair_t *pair; + + pair = (hpair_t*)malloc(sizeof(hpair_t)); + pair->key = (char*)malloc(strlen(key)+1); + pair->value = (char*)malloc(strlen(value)+1); + pair->next = next; + + strcpy(pair->key, key); + strcpy(pair->value, value); + + return pair; +} + +hpair_t *hpairnode_parse(const char *str, const char *delim, hpair_t *next) +{ + hpair_t *pair; + char *key, *value; + + pair = (hpair_t*)malloc(sizeof(hpair_t)); + pair->key = ""; + pair->value = ""; + pair->next = next; + + key = strtok_r(str, delim, &value); + + if (key != NULL) { + pair->key = (char*)malloc(strlen(key)+1); + strcpy(pair->key, key); + } + + if (value != NULL) { + pair->value = (char*)malloc(strlen(value)+1); + strcpy(pair->value, value); + } + + return pair; +} + +void hpairnode_free(hpair_t *pair) +{ + if (pair == NULL) return; + + free(pair->key); + free(pair->value); + + free(pair); +} + + +static +void hurl_dump(const hurl_t *url) +{ + const char *FUNC = "hurl_dump"; + + if (url == NULL) { + printf("(null)\n"); + return ; + } + + log_debug(FUNC, "PROTOCOL : %s", url->protocol?url->protocol:"(null)"); + log_debug(FUNC, " HOST : %s", url->host?url->host:"(null)"); + log_debug(FUNC, " PORT : %d", url->port); + log_debug(FUNC, " CONTEXT : %s", url->context?url->context:"(null)"); +} + + +hurl_t* hurl_new(const char* urlstr) +{ + int iprotocol; + int ihost; + int iport; + int len; + int size; + hurl_t *url; + char tmp[8]; + const char *FUNC = "hurl_create"; + + iprotocol = 0; + len = strlen(urlstr); + + /* find protocol */ + while (urlstr[iprotocol] != ':' && urlstr[iprotocol] != '\0') + { + iprotocol++; + } + + if (iprotocol == 0) { + log_error(FUNC, "no protocol"); + return NULL; + } + + if (iprotocol + 3 >= len) { + log_error(FUNC, "no host"); + return NULL; + } + + if ( urlstr[iprotocol] != ':' + && urlstr[iprotocol+1] != '/' + && urlstr[iprotocol+2] != '/') + { + log_error(FUNC, "no protocol"); + return NULL; + } + + /* find host */ + ihost = iprotocol + 3; + while (urlstr[ihost] != ':' + && urlstr[ihost] != '/' + && urlstr[ihost] != '\0') + { + ihost++; + } + + if (ihost == iprotocol + 1) { + log_error(FUNC, "no host"); + return NULL; + } + + /* find port */ + iport = ihost; + if (ihost + 1 < len) { + if (urlstr[ihost] == ':') { + while (urlstr[iport] != '/' && urlstr[iport] != '\0') { + iport++; + } + } + } + + url = (hurl_t*)malloc(sizeof(hurl_t)); + + url->protocol = (char*)malloc(sizeof(char)*iprotocol+1); + strncpy(url->protocol, urlstr, iprotocol); + url->protocol[iprotocol] = '\0'; + + size = ihost - iprotocol - 3; + url->host = (char*)malloc(sizeof(char)*size); + strncpy(url->host, &urlstr[iprotocol+3], size); + url->host[size] = '\0'; + + if (iport > ihost) + { + size = iport - ihost; + strncpy(tmp, &urlstr[ihost+1], size); + url->port = atoi(tmp); + } else { + url->port = 80; + } + + len = strlen(urlstr); + if (len > iport ) + { + size = len - iport; + url->context = (char*)malloc(sizeof(char)*size+1); + strncpy(url->context, &urlstr[iport], size); + url->context[size]='\0'; + } else { + url->context = NULL; + } + + hurl_dump(url); + + return url; +} + + +void hurl_free(hurl_t *url) +{ + if (url == NULL) return; + + free(url->protocol); + free(url->host); + free(url->context); + + free(url); +} + + +/* response stuff */ + +/* ------------------------------------------- + FUNCTION: hresponse_new + ---------------------------------------------*/ +hresponse_t *hresponse_new(const char* buffer) +{ + hresponse_t *res; + char *s1, *s2, *str; + hpair_t *pair; + + const char *FUNC = "hresponse_new"; + + /* create response object */ + res = (hresponse_t*)malloc(sizeof(hresponse_t)); + res->desc = ""; + res->header = NULL; + res->body = ""; + + /* *** parse spec *** */ + /* [HTTP/1.1 | 1.2] [CODE] [DESC] */ + + /* stage 1: HTTP spec */ + str = (char*)strtok_r(buffer, " ", &s2); + s1 = s2; + if (str == NULL) { log_error(FUNC, "Parse error"); return NULL; } + + strncpy(res->spec, str, 10); + + /* stage 2: http code */ + str = (char*)strtok_r(s1, " ", &s2); + s1 = s2; + if (str == NULL) { log_error(FUNC, "Parse error"); return NULL; } + + res->errcode = atoi(str); + + /* stage 3: description text */ + str = (char*)strtok_r(s1, "\r\n", &s2); + s1 = s2; + if (str == NULL) { log_error(FUNC, "Parse error"); return NULL; } + + res->desc = (char*)malloc(strlen(str)+1); + strcpy(res->desc, str); + res->desc[strlen(str)] = '\0'; + + /* *** parse header *** */ + /* [key]: [value] */ + for (;;) { + str = strtok_r(s1, "\n", &s2); + s1 = s2; + + /* check if header ends without body */ + if (str == NULL) { + return res; + } + + /* check also for end of header */ + if (!strcmp(str, "\r")) { + break; + } + + str[strlen(str)-1] = '\0'; + res->header = hpairnode_parse(str, ": ", res->header); + } + + /* *** Save body *** */ + res->body = s1; + + /* return response object */ + return res; +} + + +void hresponse_free(hresponse_t *res) +{ + /* not implemented yet!*/ +} + + diff --git a/nanohttp/nanohttp-common.h b/nanohttp/nanohttp-common.h new file mode 100644 index 0000000..d3bb702 --- /dev/null +++ b/nanohttp/nanohttp-common.h @@ -0,0 +1,142 @@ +/****************************************************************** + * $Id: nanohttp-common.h,v 1.1 2003/12/11 14:51:04 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_COMMON_H +#define NANO_HTTP_COMMON_H + + +#define HEADER_CONTENT_LENGTH "Content-Length" +#define HEADER_CONTENT_TYPE "Content-Type" +#define HEADER_HOST "Host" +#define HEADER_DATE "Date" + + +#ifndef SAVE_STR +#define SAVE_STR(str) ((str==0)?("(null)"):(str)) +#endif + +/* + hpairnode_t represents a pair (key, value) pair. + This is also a linked list. + */ +typedef struct hpair hpair_t; +struct hpair +{ + char *key; + char *value; + hpair_t *next; +}; + + +hpair_t *hpairnode_new(const char* key, const char* value, hpair_t* next); +void hpairnode_free(hpair_t *pair); + + + +typedef enum hreq_method +{ + HTTP_REQUESET_POST, + HTTP_REQUESET_GET +}hreq_method ; + + +typedef struct hurl +{ + char *protocol; + char *host; + int port; + char *context; +}hurl_t; + + +hurl_t* hurl_new(const char* urlstr); +void hurl_free(hurl_t *url); + + +/* response object */ + +typedef struct hresponse +{ + char spec[10]; + int errcode; + char *desc; + hpair_t *header; + char *body; +}hresponse_t; + +/* + PARAMS + buffer: The hole received data from socket. + */ +hresponse_t *hresponse_new(const char* buffer); +void hresponse_free(hresponse_t *res); + +/* logging stuff*/ +typedef enum log_level +{ + HLOG_DEBUG, + HLOG_INFO, + HLOG_WARN, + HLOG_ERROR, + HLOG_FATAL +}log_level_t; + +log_level_t log_set_level(log_level_t level); +log_level_t log_get_level(); + +#define log_debug1(a1) log_debug(__FUNCTION__, a1) +#define log_debug2(a1,a2) log_debug(__FUNCTION__, a1,a2) +#define log_debug3(a1,a2,a3) log_debug(__FUNCTION__, a1,a2,a3) +#define log_debug4(a1,a2,a3,a4) log_debug(__FUNCTION__, a1,a2,a3,a4) +#define log_debug5(a1,a2,a3,a4,a5) log_debug(__FUNCTION__, a1,a2,a3,a4,a5) + +#define log_info1(a1) log_info(__FUNCTION__, a1) +#define log_info2(a1,a2) log_info(__FUNCTION__, a1,a2) +#define log_info3(a1,a2,a3) log_info(__FUNCTION__, a1,a2,a3) +#define log_info4(a1,a2,a3,a4) log_info(__FUNCTION__, a1,a2,a3,a4) +#define log_info5(a1,a2,a3,a4,a5) log_info(__FUNCTION__, a1,a2,a3,a4,a5) + +#define log_warn1(a1) log_warn(__FUNCTION__, a1) +#define log_warn2(a1,a2) log_warn(__FUNCTION__, a1,a2) +#define log_warn3(a1,a2,a3) log_warn(__FUNCTION__, a1,a2,a3) +#define log_warn4(a1,a2,a3,a4) log_warn(__FUNCTION__, a1,a2,a3,a4) +#define log_warn5(a1,a2,a3,a4,a5) log_warn(__FUNCTION__, a1,a2,a3,a4,a5) + +#define log_error1(a1) log_error(__FUNCTION__, a1) +#define log_error2(a1,a2) log_error(__FUNCTION__, a1,a2) +#define log_error3(a1,a2,a3) log_error(__FUNCTION__, a1,a2,a3) +#define log_error4(a1,a2,a3,a4) log_error(__FUNCTION__, a1,a2,a3,a4) +#define log_error5(a1,a2,a3,a4,a5) log_error(__FUNCTION__, a1,a2,a3,a4,a5) + +void log_debug(const char* FUNC, const char *format, ...); +void log_info(const char* FUNC, const char *format, ...); +void log_warn(const char* FUNC, const char *format, ...); +void log_error(const char* FUNC, const char *format, ...); + +#endif + + + + + + diff --git a/nanohttp/nanohttp-socket.c b/nanohttp/nanohttp-socket.c new file mode 100644 index 0000000..1a9742b --- /dev/null +++ b/nanohttp/nanohttp-socket.c @@ -0,0 +1,324 @@ +/****************************************************************** + * $Id: nanohttp-socket.c,v 1.1 2003/12/11 14:51:04 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-socket.h> +#include <nanohttp/nanohttp-common.h> + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#ifdef HAVE_SYS_SOCKET_H +# include <sys/socket.h> +#endif + +#ifdef HAVE_ARPA_INET_H +# include <arpa/inet.h> +#endif + +#ifdef HAVE_NETDB_H +# include <netdb.h> +#endif + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#include <stdio.h> + + +/*-------------------------------------------------- + FUNCTION: hsocket_module_init +----------------------------------------------------*/ +int hsocket_module_init() +{ + /* nothing to init for unix sockets */ + return 0; +} + +/*-------------------------------------------------- + FUNCTION: hsocket_module_destroy +----------------------------------------------------*/ +void hsocket_module_destroy() +{ + /* nothing to destroy for unix sockets */ +} + + +/*-------------------------------------------------- + FUNCTION: hsocket_init +----------------------------------------------------*/ +int hsocket_init(hsocket_t *sock) +{ + /* nothing to init for unix sockets */ + /* just set the descriptor to -1 */ + *sock = -1; + return 0; +} + + +/*-------------------------------------------------- + FUNCTION: hsocket_free +----------------------------------------------------*/ +void hsocket_free(hsocket_t sock) +{ + /* nothing to free for unix sockets */ +} + + +/*-------------------------------------------------- + FUNCTION: hsocket_open +----------------------------------------------------*/ +int hsocket_open(hsocket_t *dsock, const char* hostname, int port) +{ + int sock; + struct sockaddr_in address; + struct hostent* host; + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock <= 0) return HSOCKET_CAN_NOT_CREATE_SOCKET; + + /* Get host data */ + host = gethostbyname(hostname); + if (host == NULL) return HSOCKET_CAN_NOT_GET_HOSTNAME; + + /* set server addresss */ + address.sin_family = host->h_addrtype; + address.sin_port = htons(port); + memcpy((char*)&address.sin_addr.s_addr, + host->h_addr_list[0], host->h_length); + + /* connect to the server */ + if (connect(sock, (struct sockaddr*) &address, sizeof(address)) != 0) + return HSOCKET_CAN_NOT_CONNECT; + + *dsock = sock; + return HSOCKET_OK; +} + + +/*-------------------------------------------------- + FUNCTION: hsocket_close +----------------------------------------------------*/ +void hsocket_close(hsocket_t sock) +{ + close(sock); +} + + +/*-------------------------------------------------- + FUNCTION: hsocket_send +----------------------------------------------------*/ +int hsocket_send(hsocket_t sock, const char* buffer) +{ + int size; + + size = send((int)sock, buffer, strlen(buffer), 0); + if (size == -1) + return HSOCKET_CAN_NOT_SEND; + + return HSOCKET_OK; +} + + +/*-------------------------------------------------- + FUNCTION: hsocket_recv_limit (DON'T USE!) +----------------------------------------------------*/ +int hsocket_recv_limit(hsocket_t sock, char** buffer, + const char* delim, char **rest, + int *totalBuffer, int *totalRest) +{ + ssize_t size; + int chunk=1; + char tmp[HSOCKET_MAX_BUFSIZE+1]; + int delimlen; + int fsize; + int i; + + *totalBuffer = 0; + *totalRest = 0; + delimlen = strlen(delim); + + /* calculate first size for realloc */ + if (*buffer) { + fsize = strlen(*buffer); + } else { + fsize = 0; + } + + do { + + size = recv(sock, tmp, HSOCKET_MAX_BUFSIZE, 0); + + if (size == -1) { + log_error1("Error reading from socket\n"); + return HSOCKET_CAN_NOT_RECEIVE; + } + + if (size == 0) { + break; + } + + /* section 1: find delimiter if exist */ + for (i=0;i<size-delimlen;i++) { + if (!strncmp(&tmp[i],delim,delimlen)) { + + /* ** split to buffer and rest ** */ + + /* fill buffer until i */ + *totalBuffer += i; + if (*buffer) { + *buffer = (char*)realloc(*buffer, *totalBuffer+fsize+1+HSOCKET_MAX_BUFSIZE); + strncat(*buffer, tmp, i); + *buffer[*totalBuffer+fsize] = '\0'; + } else { + *buffer = (char*)realloc(NULL, *totalBuffer+1); + strncpy(*buffer, tmp, i); + (*buffer)[*totalBuffer] = '\0'; + } + + + /* fill rest from i to size */ + if (size - (i+delimlen)+1 > 0) { + *rest = (char*)realloc(NULL, size - (i+delimlen)+1 + HSOCKET_MAX_BUFSIZE); + strcpy(*rest, &tmp[i+delimlen]); + *totalRest = size - (i+delimlen); + (*rest)[*totalRest] = '\0'; + } else { + *rest = NULL; + } + + return HSOCKET_OK; + } + } + + /* section 2: no delimiter found. so add tmp to buffer */ + *totalBuffer += size; + if (*buffer) { + *buffer = (char*)realloc(*buffer, *totalBuffer+fsize+1); + strcat(*buffer, tmp); + } else { + *buffer = (char*)realloc(NULL, *totalBuffer+1); + strcpy(*buffer, tmp); + } + + (*buffer)[*totalBuffer] = '\0'; + + chunk++; + } while (size > 0); + + return HSOCKET_OK; +} + +/*-------------------------------------------------- + FUNCTION: hsocket_recv +----------------------------------------------------*/ +int hsocket_recv(hsocket_t sock, char** buffer, int *totalSize) +{ + ssize_t size; + int chunk=1; + char tmp[HSOCKET_MAX_BUFSIZE+1]; + int fsize; + + *totalSize = 0; + + /* calculate first size for realloc */ + if (*buffer) { + fsize = strlen(*buffer); + } else { + fsize = 0; + } + + do { + + size = recv(sock, tmp, HSOCKET_MAX_BUFSIZE, 0); + + if (size == -1) { + log_error1("Error reading from socket\n"); + return HSOCKET_CAN_NOT_RECEIVE; + } + + if (size == 0) { + break; + } + + *totalSize += size; + if (*buffer) { + log_debug2("reallocation %d bytes",*totalSize+fsize+1); + *buffer = (char*)realloc((char*)*buffer, (*totalSize)+fsize+HSOCKET_MAX_BUFSIZE); + strcat(*buffer, tmp); + } else { + log_debug1("Allocating"); + *buffer = (char*)realloc(NULL, *totalSize+1); + strcpy(*buffer, tmp); + } + + log_debug1("Assigning"); + (*buffer)[*totalSize+fsize] = '\0'; + chunk++; + } while (size > 0); + + log_debug1("Returning"); + return HSOCKET_OK; +} + + + +/*-------------------------------------------------- + FUNCTION: hsocket_recv +----------------------------------------------------*/ +int hsocket_recv_cb(hsocket_t sock, + hsocket_recv_callback cb, void *userdata) +{ + ssize_t size; + char tmp[HSOCKET_MAX_BUFSIZE+1]; + + do { + + size = recv(sock, tmp, HSOCKET_MAX_BUFSIZE, 0); + + if (size == -1) { + log_error1("Error reading from socket\n"); + return HSOCKET_CAN_NOT_RECEIVE; + } + + if (size == 0) { + break; + } + + tmp[size]='\0'; + if (!cb(sock, tmp, size, userdata)) { + break; + } + + } while (size > 0); + + return HSOCKET_OK; +} + + + diff --git a/nanohttp/nanohttp-socket.h b/nanohttp/nanohttp-socket.h new file mode 100644 index 0000000..92e92e2 --- /dev/null +++ b/nanohttp/nanohttp-socket.h @@ -0,0 +1,138 @@ +/****************************************************************** + * $Id: nanohttp-socket.h,v 1.1 2003/12/11 14:51:04 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_SOCKET_H +#define NANO_HTTP_SOCKET_H + + +#define HSOCKET_OK 0 +#define HSOCKET_CAN_NOT_CREATE_SOCKET 1001 +#define HSOCKET_CAN_NOT_GET_HOSTNAME 1002 +#define HSOCKET_CAN_NOT_CONNECT 1003 +#define HSOCKET_CAN_NOT_SEND 1004 +#define HSOCKET_CAN_NOT_RECEIVE 1005 + +#define HSOCKET_MAX_BUFSIZE 1024 + +typedef int hsocket_t; + +/* + PROTOTYPE: + int my_recv_cb(hsocket_t sock, char *buffer, int size, void *userdata); + returns 1 to continue 0 to stop receiving. + */ +typedef int (*hsocket_recv_callback)(hsocket_t, char *, int, void*); + + +/* + hsocket_module_init + Returns 0 if success. + >0 if fail. + */ +int hsocket_module_init(); +void hsocket_module_destroy(); + + +/* + hsocket_init + Returns 0 if success. + >0 if fail. + */ +int hsocket_init(hsocket_t *sock); +void hsocket_free(hsocket_t sock); + + +/* + hsocket_open + Returns 0 if success + >0 if fail. + */ +int hsocket_open(hsocket_t *sock, const char* host, int port); +void hsocket_close(hsocket_t sock); + + +/* + hsocket_send + sends strlen(buffer) bytes of data + Returns 0 if success + >0 if fail + */ +int hsocket_send(hsocket_t sock, const char* buffer); + + +/* + hsocket_recv + receives everything quequed on the socket. + Sets *buffer to the received buffer. + Sets size to the received size. + You must free the buffer manually with free(). + If buffer is non zero, this functions assumes that + buffer is valid and just reallocates the given buffer. + If buffer is zero (like in the following example), + the buffer will be allocated first. + + Example: + + int size; + char *buffer; + hsocket_t sock; + + buffer = 0; + sock = ... + + if (!hsocket_recv(sock, &buffer, &size)) { + printf("Received total: %d\n", size); + printf("Received: '%s'\n", buffer); + + free(buffer); + } else { + printf("Error receiving data\n"); + } + + Returns 0 if success + >0 if fail + */ +int hsocket_recv(hsocket_t sock, char** buffer, int *size); + +int hsocket_recv_limit(hsocket_t sock, char** buffer, + const char* delim, char **rest, + int *totalBuffer, int *totalRest); + +/* + returns 1 to continue, 0 to break; + */ +int hsocket_recv_cb(hsocket_t sock, + hsocket_recv_callback cb, void *userdata); + +#endif + + + + + + + + + + + diff --git a/nanohttp/readme.txt b/nanohttp/readme.txt new file mode 100644 index 0000000..b0e04be --- /dev/null +++ b/nanohttp/readme.txt @@ -0,0 +1,2 @@ +nanohttp is a http client/server library + |