From d2c445f5d7cf21606c9878bff3e4046c283944df Mon Sep 17 00:00:00 2001 From: snowdrop Date: Sun, 19 Sep 2004 07:05:01 +0000 Subject: Added http stream feature (only input stream yet) Added DIME "client" support (very experimental) --- examples/csoap/simpleserver.c | 5 +- examples/nanohttp/httpget.c | 18 +- examples/nanohttp/postserver.c | 63 ++- libcsoap/soap-client.c | 5 +- libcsoap/soap-env.c | 616 ++++++++++++------------ libcsoap/soap-service.c | 5 +- nanohttp/Makefile.am | 7 +- nanohttp/nanohttp-client.c | 426 ++++++++++++++++- nanohttp/nanohttp-client.h | 222 +++++---- nanohttp/nanohttp-common.c | 108 ++++- nanohttp/nanohttp-common.h | 70 +-- nanohttp/nanohttp-reqres.h | 73 +++ nanohttp/nanohttp-server.c | 51 +- nanohttp/nanohttp-server.h | 6 +- nanohttp/nanohttp-socket.c | 1003 ++++++++++++++++++++-------------------- nanohttp/nanohttp-socket.h | 10 +- nanohttp/nanohttp-stream.c | 292 ++++++++++++ nanohttp/nanohttp-stream.h | 80 ++++ 18 files changed, 2058 insertions(+), 1002 deletions(-) create mode 100755 nanohttp/nanohttp-reqres.h create mode 100755 nanohttp/nanohttp-stream.c create mode 100755 nanohttp/nanohttp-stream.h diff --git a/examples/csoap/simpleserver.c b/examples/csoap/simpleserver.c index 85ea78f..a5a3318 100644 --- a/examples/csoap/simpleserver.c +++ b/examples/csoap/simpleserver.c @@ -1,5 +1,5 @@ /****************************************************************** - * $Id: simpleserver.c,v 1.8 2004/09/13 07:12:33 snowdrop Exp $ + * $Id: simpleserver.c,v 1.9 2004/09/19 07:05:01 snowdrop Exp $ * * CSOAP Project: CSOAP examples project * Copyright (C) 2003 Ferhat Ayaz @@ -88,4 +88,5 @@ int main(int argc, char *argv[]) soap_server_destroy(); return 0; -} \ No newline at end of file +} + diff --git a/examples/nanohttp/httpget.c b/examples/nanohttp/httpget.c index 319ff7f..e70469d 100644 --- a/examples/nanohttp/httpget.c +++ b/examples/nanohttp/httpget.c @@ -1,5 +1,5 @@ /****************************************************************** -* $Id: httpget.c,v 1.3 2004/08/26 17:02:24 rans Exp $ +* $Id: httpget.c,v 1.4 2004/09/19 07:05:03 snowdrop Exp $ * * CSOAP Project: A http client/server library in C (example) * Copyright (C) 2003 Ferhat Ayaz @@ -23,19 +23,10 @@ ******************************************************************/ #include -#ifdef WIN32 -#include -#include -#else #include -#endif -#ifdef WIN32 -int _tmain(int argc, _TCHAR* argv[]) -#else int main(int argc, char *argv[]) -#endif { httpc_conn_t *conn; hresponse_t *res; @@ -47,6 +38,11 @@ int main(int argc, char *argv[]) } log_set_level(HLOG_VERBOSE); + if (httpc_init(argc, argv)) + { + log_error1("Can not init httpc"); + return 1; + } conn = httpc_new(); res = httpc_get(conn, argv[1]); @@ -75,4 +71,4 @@ int main(int argc, char *argv[]) httpc_free(conn); return 0; -} \ No newline at end of file +} diff --git a/examples/nanohttp/postserver.c b/examples/nanohttp/postserver.c index 2a813b5..a28dc20 100644 --- a/examples/nanohttp/postserver.c +++ b/examples/nanohttp/postserver.c @@ -1,5 +1,5 @@ /****************************************************************** -* $Id: postserver.c,v 1.2 2004/08/26 17:02:24 rans Exp $ +* $Id: postserver.c,v 1.3 2004/09/19 07:05:03 snowdrop Exp $ * * CSOAP Project: A http client/server library in C (example) * Copyright (C) 2003 Ferhat Ayaz @@ -23,29 +23,70 @@ ******************************************************************/ #include -#ifdef WIN32 -#include -#include -#else #include -#endif + +static +void _print_binary_ascii(int n) +{ + int i,c=0; + char ascii[36]; + + for (i=0;i<32;i++) { + ascii[34-i-c] = (n & (1<sock, ""); - hsocket_send(conn->sock, "

You Posted:


"); + hsocket_send(conn->sock, "\n"); + hsocket_send(conn->sock, "

You Posted:


\n"); hsocket_nsend(conn->sock, postdata, received); + hsocket_send(conn->sock, "

Received size


\n"); + sprintf(buffer, "%d", received); + hsocket_send(conn->sock, buffer); hsocket_send(conn->sock, ""); + + _print_binary_ascii2(postdata[0]); + _print_binary_ascii2(postdata[1]); + _print_binary_ascii2(postdata[2]); + _print_binary_ascii2(postdata[3]); free(postdata); } else { @@ -62,11 +103,7 @@ void post_service(httpd_conn_t *conn, hrequest_t *req) } -#ifdef WIN32 -int _tmain(int argc, _TCHAR* argv[]) -#else int main(int argc, char *argv[]) -#endif { log_set_level(HLOG_VERBOSE); diff --git a/libcsoap/soap-client.c b/libcsoap/soap-client.c index 2c0bb4a..d287609 100644 --- a/libcsoap/soap-client.c +++ b/libcsoap/soap-client.c @@ -1,5 +1,5 @@ /****************************************************************** -* $Id: soap-client.c,v 1.6 2004/09/02 11:48:28 rans Exp $ +* $Id: soap-client.c,v 1.7 2004/09/19 07:05:03 snowdrop Exp $ * * CSOAP Project: A SOAP client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -112,4 +112,5 @@ SoapEnv* _soap_client_build_result(hresponse_t *res) } return env; -} \ No newline at end of file +} + diff --git a/libcsoap/soap-env.c b/libcsoap/soap-env.c index cd9e6d5..9c28f73 100644 --- a/libcsoap/soap-env.c +++ b/libcsoap/soap-env.c @@ -1,5 +1,5 @@ /****************************************************************** -* $Id: soap-env.c,v 1.5 2004/09/02 11:48:28 rans Exp $ +* $Id: soap-env.c,v 1.6 2004/09/19 07:05:03 snowdrop Exp $ * * CSOAP Project: A SOAP client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -55,383 +55,423 @@ Parameters: /* ---------------------------------------------------------------------------- */ /* XML Serializers (implemented at the and of this document) */ /* ---------------------------------------------------------------------------- */ -struct XmlNodeHolder { xmlNodePtr node; }; +struct XmlNodeHolder +{ + xmlNodePtr node; +}; static -void xmlbuilder_start_element(const xmlChar* element_name, int attr_count, - xmlChar **keys, xmlChar **values, void* userData); + void xmlbuilder_start_element (const xmlChar * element_name, int attr_count, + xmlChar ** keys, xmlChar ** values, + void *userData); static -void xmlbuilder_characters(const xmlChar* element_name, - const xmlChar* chars, void* userData); + void xmlbuilder_characters (const xmlChar * element_name, + const xmlChar * chars, void *userData); static -void xmlbuilder_end_element(const xmlChar* element_name, void* userData); + void xmlbuilder_end_element (const xmlChar * element_name, void *userData); /* ---------------------------------------------------------------------------- */ -SoapEnv *soap_env_new_with_fault(fault_code_t faultcode, - const char *faultstring, - const char *faultactor, - const char *detail) +SoapEnv * +soap_env_new_with_fault (fault_code_t faultcode, + const char *faultstring, + const char *faultactor, const char *detail) { - xmlDocPtr doc; - doc = soap_fault_build(faultcode, faultstring, - faultactor, detail); - if (doc == NULL) return NULL; - return soap_env_new_from_doc(doc); + xmlDocPtr doc; + doc = soap_fault_build (faultcode, faultstring, faultactor, detail); + if (doc == NULL) + return NULL; + return soap_env_new_from_doc (doc); } -SoapEnv *soap_env_new_with_response(SoapEnv* request) +SoapEnv * +soap_env_new_with_response (SoapEnv * request) { - char urn[100]; - char methodname[150]; - char methodname2[150]; - - if (request == NULL) { - log_error1("request object is NULL"); - return NULL; - } - - if (request->root == NULL) { - log_error1("request has no xml"); - return NULL; - } - - if (!soap_env_find_methodname(request, methodname)) { - return NULL; - } - - if (!soap_env_find_urn(request, urn)) { - - /* here we have no chance to find out the namespace */ - /* try to continue without namespace (urn) */ - urn[0] = '\0'; - } - - sprintf(methodname2, "%sResponse", methodname); - return soap_env_new_with_method(urn, methodname2); + char urn[100]; + char methodname[150]; + char methodname2[150]; + + if (request == NULL) + { + log_error1 ("request object is NULL"); + return NULL; + } + + if (request->root == NULL) + { + log_error1 ("request has no xml"); + return NULL; + } + + if (!soap_env_find_methodname (request, methodname)) + { + return NULL; + } + + if (!soap_env_find_urn (request, urn)) + { + + /* here we have no chance to find out the namespace */ + /* try to continue without namespace (urn) */ + urn[0] = '\0'; + } + + sprintf (methodname2, "%sResponse", methodname); + return soap_env_new_with_method (urn, methodname2); } -SoapEnv *soap_env_new_with_method(const char *urn, const char *method) +SoapEnv * +soap_env_new_with_method (const char *urn, const char *method) { - xmlDocPtr env; - SoapEnv *call; - xmlChar buffer[1054]; + xmlDocPtr env; + SoapEnv *call; + xmlChar buffer[1054]; - log_verbose2("URN = '%s'", urn); - log_verbose2("Method = '%s'",method); + log_verbose2 ("URN = '%s'", urn); + log_verbose2 ("Method = '%s'", method); - xmlStrPrintf(buffer, 1054, BAD_CAST _SOAP_MSG_TEMPLATE_, - soap_env_ns, soap_env_enc, soap_xsi_ns, + xmlStrPrintf (buffer, 1054, BAD_CAST _SOAP_MSG_TEMPLATE_, + soap_env_ns, soap_env_enc, soap_xsi_ns, soap_xsd_ns, BAD_CAST method, BAD_CAST urn, BAD_CAST method); - env = xmlParseDoc(buffer); - call = soap_env_new_from_doc(env); + env = xmlParseDoc (buffer); + call = soap_env_new_from_doc (env); - return call; + return call; } xmlNodePtr -soap_env_add_item(SoapEnv *call, const char *type, - const char *name, const char *value) +soap_env_add_item (SoapEnv * call, const char *type, + const char *name, const char *value) { - xmlNodePtr newnode; + xmlNodePtr newnode; - newnode = xmlNewTextChild(call->cur, NULL, BAD_CAST name, BAD_CAST value); + newnode = xmlNewTextChild (call->cur, NULL, BAD_CAST name, BAD_CAST value); - if (newnode == NULL) { - log_error1("Can not create new xml node"); - return NULL; - } + if (newnode == NULL) + { + log_error1 ("Can not create new xml node"); + return NULL; + } - if (type) { - if (!xmlNewProp(newnode, BAD_CAST "xsi:type", BAD_CAST type)) { - log_error1("Can not create new xml attribute"); - return NULL; - } - } + if (type) + { + if (!xmlNewProp (newnode, BAD_CAST "xsi:type", BAD_CAST type)) + { + log_error1 ("Can not create new xml attribute"); + return NULL; + } + } - return newnode; + return newnode; } xmlNodePtr -soap_env_add_itemf(SoapEnv *call, const char *type, - const char *name, const char *format, ...) +soap_env_add_itemf (SoapEnv * call, const char *type, + const char *name, const char *format, ...) { - va_list ap; - char buffer[1054]; + va_list ap; + char buffer[1054]; - va_start(ap, format); - vsprintf(buffer, format, ap); - va_end(ap); + va_start (ap, format); + vsprintf (buffer, format, ap); + va_end (ap); - return soap_env_add_item(call, type, name, buffer); + return soap_env_add_item (call, type, name, buffer); } void -soap_env_add_custom(SoapEnv *call, void *obj, XmlSerializerCallback cb, - const char *type, const char *name) +soap_env_add_custom (SoapEnv * call, void *obj, XmlSerializerCallback cb, + const char *type, const char *name) { - struct XmlNodeHolder holder; + struct XmlNodeHolder holder; - holder.node = soap_env_get_method(call); + holder.node = soap_env_get_method (call); - cb(obj, BAD_CAST name, - xmlbuilder_start_element, - xmlbuilder_characters, - xmlbuilder_end_element, &holder); + cb (obj, BAD_CAST name, + xmlbuilder_start_element, + xmlbuilder_characters, xmlbuilder_end_element, &holder); } xmlNodePtr -soap_env_push_item(SoapEnv *call, const char *type, - const char *name) +soap_env_push_item (SoapEnv * call, const char *type, const char *name) { - xmlNodePtr node; + xmlNodePtr node; - node = soap_env_add_item(call, type, name, ""); + node = soap_env_add_item (call, type, name, ""); - if (node) { - call->cur = node; - } + if (node) + { + call->cur = node; + } - return node; + return node; } void -soap_env_pop_item(SoapEnv *call) +soap_env_pop_item (SoapEnv * call) { - call->cur = call->cur->parent; + call->cur = call->cur->parent; } -void soap_env_free(SoapEnv *env) +void +soap_env_free (SoapEnv * env) { - if (env) { - if (env->root) { - xmlFreeDoc(env->root->doc); - } - free(env); - } + if (env) + { + if (env->root) + { + xmlFreeDoc (env->root->doc); + } + free (env); + } } -SoapEnv *soap_env_new_from_doc(xmlDocPtr doc) +SoapEnv * +soap_env_new_from_doc (xmlDocPtr doc) { - SoapEnv *env; - xmlNodePtr node; - - if (doc == NULL) { - log_error1("Can not create xml document!"); - return NULL; - } - - node = xmlDocGetRootElement(doc); - if (node == NULL) { - log_error1("xml document is empty!"); - return NULL; - } - - env = (SoapEnv*)malloc(sizeof(SoapEnv)); - - /* set root */ - env->root = node; - - /* set method root - set call->cur (current node) to . - xpath: //Envelope/Body/ - */ - node = soap_xml_get_children(env->root); - env->cur = soap_xml_get_children(node); - - return env; + SoapEnv *env; + xmlNodePtr node; + + if (doc == NULL) + { + log_error1 ("Can not create xml document!"); + return NULL; + } + + node = xmlDocGetRootElement (doc); + if (node == NULL) + { + log_error1 ("xml document is empty!"); + return NULL; + } + + env = (SoapEnv *) malloc (sizeof (SoapEnv)); + + /* set root */ + env->root = node; + + /* set method root + set call->cur (current node) to . + xpath: //Envelope/Body/ + */ + node = soap_xml_get_children (env->root); + env->cur = soap_xml_get_children (node); + + return env; } -SoapEnv *soap_env_new_from_buffer(const char* buffer) +SoapEnv * +soap_env_new_from_buffer (const char *buffer) { - xmlDocPtr doc; - SoapEnv *env; + xmlDocPtr doc; + SoapEnv *env; - if (buffer == NULL) return NULL; + if (buffer == NULL) + return NULL; - doc = xmlParseDoc(BAD_CAST buffer); - if (doc == NULL) return NULL; + doc = xmlParseDoc (BAD_CAST buffer); + if (doc == NULL) + return NULL; - env = soap_env_new_from_doc(doc); - if (env == NULL) { - xmlFreeDoc(doc); - return NULL; - } + env = soap_env_new_from_doc (doc); + if (env == NULL) + { + xmlFreeDoc (doc); + return NULL; + } - return env; + return env; } xmlNodePtr -soap_env_get_body(SoapEnv* env) +soap_env_get_body (SoapEnv * env) { - xmlNodePtr node; - - if (env == NULL) { - log_error1("env object is NULL"); - return NULL; - } - - if (env->root == NULL) { - log_error1("env has no xml"); - return NULL; - } - - node = soap_xml_get_children(env->root); - - while (node != NULL) { - if (!xmlStrcmp(node->name, BAD_CAST "Body")) - return node; - node = soap_xml_get_next(node); - } - - log_error1("Node Body tag found!"); - return NULL; + xmlNodePtr node; + + if (env == NULL) + { + log_error1 ("env object is NULL"); + return NULL; + } + + if (env->root == NULL) + { + log_error1 ("env has no xml"); + return NULL; + } + + node = soap_xml_get_children (env->root); + + while (node != NULL) + { + if (!xmlStrcmp (node->name, BAD_CAST "Body")) + return node; + node = soap_xml_get_next (node); + } + + log_error1 ("Node Body tag found!"); + return NULL; } xmlNodePtr -soap_env_get_method(SoapEnv* env) +soap_env_get_method (SoapEnv * env) { - xmlNodePtr body; + xmlNodePtr body; - body = soap_env_get_body(env); - if (body == NULL) { - log_verbose1("body is NULL"); - return NULL; - } + body = soap_env_get_body (env); + if (body == NULL) + { + log_verbose1 ("body is NULL"); + return NULL; + } - /* mehtod is the first child */ - return soap_xml_get_children(body); + /* mehtod is the first child */ + return soap_xml_get_children (body); } xmlNodePtr -_soap_env_get_body(SoapEnv* env) +_soap_env_get_body (SoapEnv * env) { - xmlNodePtr body; - xmlNodeSetPtr nodeset; - xmlXPathObjectPtr xpathobj; - - if (env == NULL) { - log_error1("env object is NULL"); - return NULL; - } - - if (env->root == NULL) { - log_error1("env has no xml"); - return NULL; - } - - /* - find tag find out namespace - xpath: //Envelope/Body/ - */ - xpathobj = soap_xpath_eval(env->root->doc, "//Envelope/Body"); - - if (!xpathobj) { - log_error1("No Body (xpathobj)!"); - return NULL; - } - - nodeset = xpathobj->nodesetval; - if (!nodeset) { - log_error1("No Body (nodeset)!"); - xmlXPathFreeObject(xpathobj); - return NULL; - } - - if (nodeset->nodeNr < 1) { - log_error1("No Body (nodeNr)!"); - xmlXPathFreeObject(xpathobj); - return NULL; - } - - body = nodeset->nodeTab[0]; /* body is */ - xmlXPathFreeObject(xpathobj); - return body; + xmlNodePtr body; + xmlNodeSetPtr nodeset; + xmlXPathObjectPtr xpathobj; + + if (env == NULL) + { + log_error1 ("env object is NULL"); + return NULL; + } + + if (env->root == NULL) + { + log_error1 ("env has no xml"); + return NULL; + } + + /* + find tag find out namespace + xpath: //Envelope/Body/ + */ + xpathobj = soap_xpath_eval (env->root->doc, "//Envelope/Body"); + + if (!xpathobj) + { + log_error1 ("No Body (xpathobj)!"); + return NULL; + } + + nodeset = xpathobj->nodesetval; + if (!nodeset) + { + log_error1 ("No Body (nodeset)!"); + xmlXPathFreeObject (xpathobj); + return NULL; + } + + if (nodeset->nodeNr < 1) + { + log_error1 ("No Body (nodeNr)!"); + xmlXPathFreeObject (xpathobj); + return NULL; + } + + body = nodeset->nodeTab[0]; /* body is */ + xmlXPathFreeObject (xpathobj); + return body; } -int soap_env_find_urn(SoapEnv *env, char *urn) +int +soap_env_find_urn (SoapEnv * env, char *urn) { - xmlNsPtr ns; - xmlNodePtr body, node; - - body = soap_env_get_body(env); - if (body == NULL) { - log_verbose1("body is NULL"); - return 0; - } - - /* node is the first child */ - node = soap_xml_get_children(body); - - if (node == NULL) { - log_error1("No namespace found"); - return 0; - } - - if (node->ns && node->ns->prefix) { - ns = xmlSearchNs(body->doc, node, node->ns->prefix); - if (ns != NULL) { - strcpy(urn, (char*)ns->href); - return 1; /* namespace found! */ - } - } - - log_error1("No namespace found. Returning 0"); - return 0; + xmlNsPtr ns; + xmlNodePtr body, node; + + body = soap_env_get_body (env); + if (body == NULL) + { + log_verbose1 ("body is NULL"); + return 0; + } + + /* node is the first child */ + node = soap_xml_get_children (body); + + if (node == NULL) + { + log_error1 ("No namespace found"); + return 0; + } + + if (node->ns && node->ns->prefix) + { + ns = xmlSearchNs (body->doc, node, node->ns->prefix); + if (ns != NULL) + { + strcpy (urn, (char *) ns->href); + return 1; /* namespace found! */ + } + } + + log_error1 ("No namespace found. Returning 0"); + return 0; } -int soap_env_find_methodname(SoapEnv *env, char *method) +int +soap_env_find_methodname (SoapEnv * env, char *method) { - xmlNodePtr body, node; + xmlNodePtr body, node; - body = soap_env_get_body(env); - if (body == NULL) return 0; + body = soap_env_get_body (env); + if (body == NULL) + return 0; - node = soap_xml_get_children(body); /* node is the first child */ + node = soap_xml_get_children (body); /* node is the first child */ - if (node == NULL) { - log_error1("No method found"); - return 0; - } + if (node == NULL) + { + log_error1 ("No method found"); + return 0; + } - if (node->name == NULL) { - log_error1("No methodname found"); - return 0; + if (node->name == NULL) + { + log_error1 ("No methodname found"); + return 0; - } + } - strcpy(method, (const char *)node->name); + strcpy (method, (const char *) node->name); - return 1; + return 1; } @@ -441,43 +481,51 @@ int soap_env_find_methodname(SoapEnv *env, char *method) /* ------------------------------------------------------------------ */ -static -void xmlbuilder_start_element(const xmlChar* element_name, int attr_count, xmlChar **keys, xmlChar **values, void* userData) +static void +xmlbuilder_start_element (const xmlChar * element_name, int attr_count, + xmlChar ** keys, xmlChar ** values, void *userData) { - struct XmlNodeHolder *holder = (struct XmlNodeHolder*)userData; - xmlNodePtr parent = NULL; + struct XmlNodeHolder *holder = (struct XmlNodeHolder *) userData; + xmlNodePtr parent = NULL; - if (holder == NULL) return; - parent = holder->node; - if (parent == NULL) return; + if (holder == NULL) + return; + parent = holder->node; + if (parent == NULL) + return; - holder->node = xmlNewChild(parent, NULL, element_name, NULL); + holder->node = xmlNewChild (parent, NULL, element_name, NULL); } -static -void xmlbuilder_characters(const xmlChar* element_name, const xmlChar* chars, void* userData) +static void +xmlbuilder_characters (const xmlChar * element_name, const xmlChar * chars, + void *userData) { - struct XmlNodeHolder *holder = (struct XmlNodeHolder*)userData; - xmlNodePtr parent = NULL; + struct XmlNodeHolder *holder = (struct XmlNodeHolder *) userData; + xmlNodePtr parent = NULL; - if (holder == NULL) return; - parent = holder->node; - if (parent == NULL) return; + if (holder == NULL) + return; + parent = holder->node; + if (parent == NULL) + return; - xmlNewTextChild(parent, NULL, element_name, chars); + xmlNewTextChild (parent, NULL, element_name, chars); } -static -void xmlbuilder_end_element(const xmlChar * element_name, void* userData) +static void +xmlbuilder_end_element (const xmlChar * element_name, void *userData) { - struct XmlNodeHolder *holder = (struct XmlNodeHolder*)userData; - xmlNodePtr parent = NULL; + struct XmlNodeHolder *holder = (struct XmlNodeHolder *) userData; + xmlNodePtr parent = NULL; - if (holder == NULL) return; - parent = holder->node; - if (parent == NULL) return; + if (holder == NULL) + return; + parent = holder->node; + if (parent == NULL) + return; - holder->node = parent->parent; + holder->node = parent->parent; } diff --git a/libcsoap/soap-service.c b/libcsoap/soap-service.c index 8f87fb5..e8ef81d 100644 --- a/libcsoap/soap-service.c +++ b/libcsoap/soap-service.c @@ -1,5 +1,5 @@ /****************************************************************** -* $Id: soap-service.c,v 1.3 2004/08/26 17:06:18 rans Exp $ +* $Id: soap-service.c,v 1.4 2004/09/19 07:05:03 snowdrop Exp $ * * CSOAP Project: A SOAP client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -85,4 +85,5 @@ void soap_service_free(SoapService *service) free(service); log_verbose1("leave with success"); -} \ No newline at end of file +} + diff --git a/nanohttp/Makefile.am b/nanohttp/Makefile.am index c8ba204..ba3cf78 100644 --- a/nanohttp/Makefile.am +++ b/nanohttp/Makefile.am @@ -4,12 +4,15 @@ h_sources = nanohttp-common.h\ nanohttp-socket.h\ nanohttp-client.h\ -nanohttp-server.h +nanohttp-server.h\ +nanohttp-reqres.h\ +nanohttp-stream.h cc_sources = nanohttp-common.c\ nanohttp-socket.c\ nanohttp-client.c\ -nanohttp-server.c +nanohttp-server.c\ +nanohttp-stream.c library_includedir=$(includedir)/$(NANOHTTP_LIBRARY_NAME)-$(NANOHTTP_API_VERSION)/$(NANOHTTP_LIBRARY_NAME) library_include_HEADERS = $(h_sources) diff --git a/nanohttp/nanohttp-client.c b/nanohttp/nanohttp-client.c index ee02c59..13972a1 100644 --- a/nanohttp/nanohttp-client.c +++ b/nanohttp/nanohttp-client.c @@ -1,5 +1,5 @@ /****************************************************************** -* $Id: nanohttp-client.c,v 1.18 2004/09/01 07:58:00 snowdrop Exp $ +* $Id: nanohttp-client.c,v 1.19 2004/09/19 07:05:03 snowdrop Exp $ * * CSOAP Project: A http client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -58,7 +58,10 @@ httpc_new() hsocket_init(&res->sock); res->header = NULL; res->url = NULL; - + res->version = HTTP_1_1; + res->_dime_package_nr = 0; + res->_dime_sent_bytes = 0; + res->_is_chunked = 0; return res; } @@ -167,6 +170,49 @@ httpc_send_header(httpc_conn_t * conn) return status; } +/*-------------------------------------------------- +FUNCTION: httpc_set_transfer_encoding +DESC: +----------------------------------------------------*/ +void httpc_set_transfer_encoding(httpc_conn_t *conn, const char* encoding) +{ + httpc_set_header(conn, HEADER_TRANSFER_ENCODING, encoding); + + if (!strcmp(encoding, TRANSFER_ENCODING_CHUNKED)) + conn->_is_chunked = 1; +} + +/*-------------------------------------------------- +FUNCTION: httpc_set_transfer_encoding +DESC: +----------------------------------------------------*/ +int httpc_send_data(httpc_conn_t *conn, const unsigned char* bytes, size_t size) +{ + int status; + char chunked[15]; + + if (conn->_is_chunked) + { + sprintf(chunked,"%x\r\n",size); + status = hsocket_send(conn->sock, chunked); + if (status != HSOCKET_OK) + return status; + } + + status = hsocket_nsend(conn->sock, bytes, size); + + if (conn->_is_chunked) + { + status = hsocket_send(conn->sock, "\r\n"); + if (status != HSOCKET_OK) + return status; + } + + return status; +} + + + static hresponse_t * httpc_receive_header(hsocket_t sock) @@ -196,10 +242,6 @@ httpc_receive_header(hsocket_t sock) } for (i = 0; i < status - 2; i++) { - /* - * log_debug5("%d -> '%c' (%d, %d)", buffer[i], - * buffer[i], buffer[i+1], buffer[i+2]); - */ if (buffer[i] == '\n') { if (buffer[i + 1] == '\n') { @@ -353,11 +395,11 @@ httpc_receive_with_chunked_encoding(httpc_conn_t * conn, chunk_size_cur = 0; while (1) { - if (hbufsocket_read(&bufsock, &chunk_size_str[chunk_size_cur], 1)) { log_error1("Can not read from socket"); return 9; } + log_debug2("chunk_size_str[chunk_size_cur] = '%c'", chunk_size_str[chunk_size_cur]); @@ -369,6 +411,8 @@ httpc_receive_with_chunked_encoding(httpc_conn_t * conn, && chunk_size_str[chunk_size_cur] != ';') { chunk_size_cur++; } + /* TODO (#1#): check for chunk_size_cur >= 25 */ + } /* while (1) */ chunk_size = strtol(chunk_size_str, (char **) NULL, 16); /* hex to dec */ @@ -475,6 +519,14 @@ httpc_receive_response(httpc_conn_t * conn, hresponse_t *res; int status; + /* check if chunked */ + if (conn->_is_chunked) + { + status = hsocket_send(conn->sock, "0\r\n\r\n"); + if (status != HSOCKET_OK) + return status; + } + /* receive header */ log_verbose1("receiving header"); res = httpc_receive_header(conn->sock); @@ -510,6 +562,51 @@ httpc_receive_response(httpc_conn_t * conn, return -1; } +static +int +_httpc_receive_response(httpc_conn_t * conn, + httpc_response_start_callback start_cb, + httpc_response_callback cb, void *userdata) +{ + hresponse_t *res; + int status, counter=1; + byte_t buffer[MAX_SOCKET_BUFFER_SIZE+1]; + + /* check if chunked */ + if (conn->_is_chunked) + { + status = hsocket_send(conn->sock, "0\r\n\r\n"); + if (status != HSOCKET_OK) + return status; + } + + /* Create response object */ + res = hresponse_new_from_socket(conn->sock); + if (res == NULL) + { + log_error1("hresponse_new_from_socket() failed!"); + return -1; + } + + /* Invoke callback */ + start_cb(conn, userdata, res->header, res->spec, + res->errcode, res->desc); + + while (http_input_stream_is_ready(res->in)) + { + status = http_input_stream_read(res->in, buffer, MAX_SOCKET_BUFFER_SIZE); + if (status < 0) + { + log_error2("Stream read error: %d", status); + return -1; + } + + cb(counter++, conn, userdata, status, buffer); + } + + return HSOCKET_OK; +} + /*-------------------------------------------------- FUNCTION: httpc_talk_to_server DESC: This function is the heart of the httpc @@ -596,14 +693,16 @@ httpc_talk_to_server(hreq_method method, httpc_conn_t * conn, if (method == HTTP_REQUEST_GET) { /* Set GET Header */ - sprintf(buffer, "GET %s HTTP/1.1\r\n", - (url->context) ? url->context : ("/")); + sprintf(buffer, "GET %s HTTP/%s\r\n", + (url->context) ? url->context : ("/"), + (conn->version == HTTP_1_0)?"1.0":"1.1"); } else if (method == HTTP_REQUEST_POST) { /* Set POST Header */ - sprintf(buffer, "POST %s HTTP/1.1\r\n", - (url->context) ? url->context : ("/")); + sprintf(buffer, "POST %s HTTP/%s\r\n", + (url->context) ? url->context : ("/"), + (conn->version == HTTP_1_0)?"1.0":"1.1"); } else { log_error1("Unknown method type!"); @@ -648,7 +747,7 @@ httpc_get_cb(httpc_conn_t * conn, const char *urlstr, if (status != HSOCKET_OK) return status; - status = httpc_receive_response(conn, start_cb, cb, userdata); + status = _httpc_receive_response(conn, start_cb, cb, userdata); return status; } @@ -668,7 +767,7 @@ int httpc_post_cb(httpc_conn_t * conn, const char *urlstr, httpc_response_start_callback start_cb, httpc_response_callback cb, int content_size, - char *content, void *userdata) + const char *content, void *userdata) { int status; char buffer[255]; @@ -689,11 +788,11 @@ httpc_post_cb(httpc_conn_t * conn, const char *urlstr, } -/* - * ====================================================== The following - * functions are used internally to wrap the httpc_x_cb (x = get|post) - * functions. ====================================================== - */ +/* ====================================================== + The following + functions are used internally to wrap the httpc_x_cb +(x = get|post) functions. +======================================================*/ static void httpc_custom_res_callback(int counter, httpc_conn_t * conn, @@ -789,6 +888,297 @@ httpc_post(httpc_conn_t * conn, const char *url, } +/* --------------------------------------------------- + DIME support functions httpc_dime_* function set +-----------------------------------------------------*/ +int httpc_dime_begin(httpc_conn_t *conn, const char *url) +{ + int status; + httpc_set_header(conn, HEADER_CONTENT_TYPE, "application/dime"); + + status = httpc_talk_to_server(HTTP_REQUEST_POST, conn, url); + return status; +} + +static _print_binary_ascii(int n) +{ + int i,c=0; + char ascii[36]; + + for (i=0;i<32;i++) { + ascii[34-i-c] = (n & (1<_dime_package_nr == 0) + header[0] |= DIME_FIRST_PACKAGE; + + if (last) + header[0] |= DIME_LAST_PACKAGE; + + header[1] = DIME_TYPE_URI; + + tmp = strlen(dime_options); + header[2] = tmp >> 8; + header[3] = tmp; + + tmp = strlen(id); + header[4] = tmp >> 8; + header[5] = tmp; + + tmp = strlen(content_type); + header[6] = tmp >> 8; + header[7] = tmp; + + header[8] = content_length >> 24; + header[9] = content_length >> 16; + header[10] = content_length >> 8; + header[11] = content_length; + + + _print_binary_ascii32(header[0], header[1], header[2], header[3]); + _print_binary_ascii32(header[4], header[5], header[6], header[7]); + _print_binary_ascii32(header[8], header[9], header[10], header[11]); + + status = httpc_send_data(conn, header, 12); + if (status != HSOCKET_OK) + return status; + + status = httpc_send_data(conn, (const unsigned char*)dime_options, strlen(dime_options)); + if (status != HSOCKET_OK) + return status; + + status = httpc_send_data(conn, (const unsigned char*)id, strlen(id)); + if (status != HSOCKET_OK) + return status; + + status = httpc_send_data(conn, (const unsigned char*)content_type, strlen(content_type)); + if (status != HSOCKET_OK) + return status; + + return status; +} + +int httpc_dime_send_data(httpc_conn_t* conn, int size, unsigned char* data) +{ + return httpc_send_data(conn, data, size); +} + +int httpc_dime_get_response_cb(httpc_conn_t *conn, + httpc_response_start_callback start_cb, + httpc_response_callback cb, void *userdata) +{ + int status; + + status = httpc_receive_response(conn, start_cb, cb, userdata); + return status; +} + + +hresponse_t* httpc_dime_get_response(httpc_conn_t *conn) +{ + int status; + hresponse_t *res; + + res = hresponse_new(); + status = httpc_dime_get_response_cb(conn, httpc_custom_start_callback, + httpc_custom_res_callback, res); + + if (status != 0) { + hresponse_free(res); + return NULL; + } + + return res; +} + + +/* --------------------------------------------------- + MIME support functions httpc_mime_* function set +-----------------------------------------------------*/ + +static +void _httpc_mime_get_boundary(httpc_conn_t *conn, char *dest) +{ + sprintf(dest, "---=_NH_%p", conn); + log_verbose2("boundary= \"%s\"", dest); +} + +int httpc_mime_post_begin(httpc_conn_t *conn, const char *url, + const char* related_start, + const char* related_start_info, + const char* related_type) +{ + int status; + char buffer[300]; + char temp[75]; + char boundary[75]; + + /* + Set Content-type + Set multipart/related parameter + type=..; start=.. ; start-info= ..; boundary=... + + */ + sprintf(buffer, "multipart/related;"); + + if (related_type) { + snprintf(temp, 75, " type=\"%s\";", related_type); + strcat(buffer, temp); + } + + if (related_start) { + snprintf(temp, 75, " start=\"%s\";", related_start); + strcat(buffer, temp); + } + + if (related_start_info) { + snprintf(temp, 75, " start-info=\"%s\";", related_start_info); + strcat(buffer, temp); + } + + _httpc_mime_get_boundary(conn, boundary); + snprintf(temp, 75, " boundary=\"%s\"", boundary); + strcat(buffer, temp); + + httpc_set_header(conn, HEADER_CONTENT_TYPE, buffer); + + status = httpc_talk_to_server(HTTP_REQUEST_POST, conn, url); + return status; +} + + +int httpc_mime_post_next(httpc_conn_t *conn, + const char* content_id, + const char* content_type, + const char* transfer_encoding) +{ + int status; + char buffer[512]; + char boundary[75]; + + /* Get the boundary string */ + _httpc_mime_get_boundary(conn, boundary); + sprintf(buffer, "\r\n--%s\r\n", boundary); + + /* Send boundary */ + status = httpc_send_data(conn, (const unsigned char*)buffer, strlen(buffer)); + /* status = hsocket_send(conn->sock, buffer);*/ + if (status != HSOCKET_OK) + return status; + + /* Send Content header */ + sprintf(buffer, "%s: %s\r\n%s: %s\r\n%s: %s\r\n\r\n", + HEADER_CONTENT_TYPE, content_type, + HEADER_CONTENT_TRANSFER_ENCODING, transfer_encoding, + HEADER_CONTENT_ID, content_id); + + status = httpc_send_data(conn, (const unsigned char*)buffer, strlen(buffer)); + + return status; +} + + +int httpc_mime_post_send(httpc_conn_t *conn, size_t size, const unsigned char* data) +{ + int status; + char buffer[15]; + + status = httpc_send_data(conn, (const unsigned char*)data, size); + if (status != HSOCKET_OK) + return status; + + + return status; +} + + +int httpc_mime_post_end_cb(httpc_conn_t *conn, + httpc_response_start_callback start_cb, + httpc_response_callback cb, void *userdata) +{ + + int status; + char buffer[512]; + char boundary[75]; + char chunked[15]; + + /* Get the boundary string */ + _httpc_mime_get_boundary(conn, boundary); + sprintf(buffer, "\r\n--%s--\r\n\r\n", boundary); + + /* Send boundary */ + status = httpc_send_data(conn, (unsigned char*)buffer, strlen(buffer)); + if (status != HSOCKET_OK) + return status; + + /*status = hsocket_send(conn->sock, buffer);*/ + + status = httpc_receive_response(conn, start_cb, cb, userdata); + return status; +} + + +hresponse_t *httpc_mime_post_end(httpc_conn_t *conn) +{ + int status; + hresponse_t *res; + + res = hresponse_new(); + status = httpc_mime_post_end_cb(conn, httpc_custom_start_callback, + httpc_custom_res_callback, res); + + if (status != 0) { + hresponse_free(res); + return NULL; + } + + return res; +} + /* * POST Module diff --git a/nanohttp/nanohttp-client.h b/nanohttp/nanohttp-client.h index f937f00..6a53f9d 100644 --- a/nanohttp/nanohttp-client.h +++ b/nanohttp/nanohttp-client.h @@ -1,92 +1,134 @@ -/****************************************************************** - * $Id: nanohttp-client.h,v 1.7 2004/08/31 16:34:08 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 - ******************************************************************/ -#ifndef NANO_HTTP_CLIENT_H -#define NANO_HTTP_CLIENT_H - - -#include -#include - - -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*); +/****************************************************************** + * $Id: nanohttp-client.h,v 1.8 2004/09/19 07:05:03 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 +#include +#include + +typedef struct httpc_conn +{ + hsocket_t sock; + hpair_t *header; + hurl_t *url; + http_version_t version; + /* + -1 : last dime package + 0 : no dime connection + >0 : dime package number + */ + int _dime_package_nr; + long _dime_sent_bytes; + int _is_chunked; +}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*); int httpc_init(int argc, char *argv[]); -httpc_conn_t* httpc_new(); -void httpc_free(httpc_conn_t* conn); - -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, - int conten_size, 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, int content_size, - char *content, void *userdata); - - - -/* - Chunked POST Module - */ - -/* Returns 0 if success, >0 otherwise */ -/* do not use this -int httpc_post_open(httpc_conn_t *conn, const char *url); - -int httpc_post_send(httpc_conn_t *conn, const char* buffer, int bufsize); -hresponse_t *httpc_post_finish(httpc_conn_t *conn); -int httpc_post_finish_cb(httpc_conn_t *conn, - httpc_response_start_callback start_cb, - httpc_response_callback cb, void *userdata); -*/ - -#endif - +httpc_conn_t* httpc_new(); +void httpc_free(httpc_conn_t* conn); + +int httpc_set_header(httpc_conn_t *conn, const char* key, const char* value); +void httpc_set_transfer_encoding(httpc_conn_t *conn, const char* encoding); + +hresponse_t *httpc_get(httpc_conn_t *conn, const char *url); +hresponse_t *httpc_post(httpc_conn_t *conn, const char *url, + int conten_size, 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, int content_size, + const char *content, void *userdata); + +/* + DIME support httpc_dime_* function set +*/ +int httpc_dime_begin(httpc_conn_t *conn, const char *url); +int httpc_dime_next(httpc_conn_t* conn, long content_length, + const char *content_type, const char *id, + const char *dime_options, int last); +int httpc_dime_send_data(httpc_conn_t* conn, int size, unsigned char* data); +hresponse_t* httpc_dime_get_response(httpc_conn_t *conn); +int httpc_dime_get_response_cb(httpc_conn_t *conn, + httpc_response_start_callback start_cb, + httpc_response_callback cb, void *userdata); + +/* + MIME support httpc_mime_* function set +*/ + +int httpc_mime_post_begin(httpc_conn_t *conn, const char *url, + const char* related_start, + const char* related_start_info, + const char* related_type); + +int httpc_mime_post_next(httpc_conn_t *conn, + const char* content_id, + const char* content_type, + const char* transfer_encoding); + +int httpc_mime_post_send(httpc_conn_t *conn, size_t size, const unsigned char* data); +hresponse_t *httpc_mime_post_end(httpc_conn_t *conn); +int httpc_mime_post_end_cb(httpc_conn_t *conn, + httpc_response_start_callback start_cb, + httpc_response_callback cb, void *userdata); + + +/* + Chunked POST Module + */ + +/* Returns 0 if success, >0 otherwise */ +/* do not use this +int httpc_post_open(httpc_conn_t *conn, const char *url); + +int httpc_post_send(httpc_conn_t *conn, const char* buffer, int bufsize); +hresponse_t *httpc_post_finish(httpc_conn_t *conn); +int httpc_post_finish_cb(httpc_conn_t *conn, + 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 index b96c0bc..fb67595 100644 --- a/nanohttp/nanohttp-common.c +++ b/nanohttp/nanohttp-common.c @@ -1,5 +1,5 @@ /****************************************************************** -* $Id: nanohttp-common.c,v 1.11 2004/09/01 07:58:08 snowdrop Exp $ +* $Id: nanohttp-common.c,v 1.12 2004/09/19 07:05:03 snowdrop Exp $ * * CSOAP Project: A http client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -23,6 +23,7 @@ ******************************************************************/ #include +#include #include #include @@ -657,6 +658,111 @@ hresponse_new() return res; } +static +hresponse_t * +_hresponse_parse_header(const char *buffer) +{ + hresponse_t *res; + char *s1, *s2, *str; + + /* create response object */ + res = hresponse_new(); + + /* *** parse spec *** */ + /* [HTTP/1.1 | 1.2] [CODE] [DESC] */ + + /* stage 1: HTTP spec */ + str = (char *) strtok_r((char *) buffer, " ", &s2); + s1 = s2; + if (str == NULL) { + log_error1("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_error1("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_error1("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); + } + + /* return response object */ + return res; +} + +hresponse_t * +hresponse_new_from_socket(hsocket_t sock) +{ + int i=0, status; + hresponse_t *res; + char buffer[MAX_HEADER_SIZE+1]; + + /* Read header */ + while (i 3) + { + if (!strcmp(&(buffer[i-1]), "\n\n") || + !strcmp(&(buffer[i-2]), "\n\r\n")) + break; + } + i++; + } + + /* Create response */ + res = _hresponse_parse_header(buffer); + if (res == NULL) + { + log_error1("Header parse error"); + return NULL; + } + + /* Create input stream */ + res->in = http_input_stream_new(sock, res->header); + + return res; +} /* * ------------------------------------------- FUNCTION: diff --git a/nanohttp/nanohttp-common.h b/nanohttp/nanohttp-common.h index 455e9ed..0d765d8 100644 --- a/nanohttp/nanohttp-common.h +++ b/nanohttp/nanohttp-common.h @@ -1,5 +1,5 @@ /****************************************************************** - * $Id: nanohttp-common.h,v 1.10 2004/09/14 15:31:24 snowdrop Exp $ + * $Id: nanohttp-common.h,v 1.11 2004/09/19 07:05:03 snowdrop Exp $ * * CSOAP Project: A http client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -27,17 +27,24 @@ #define HEADER_CONTENT_LENGTH "Content-Length" #define HEADER_CONTENT_TYPE "Content-Type" +#define HEADER_CONTENT_ID "Content-Id" +#define HEADER_CONTENT_TRANSFER_ENCODING "Content-Transfer-Encoding" #define HEADER_TRANSFER_ENCODING "Transfer-Encoding" #define HEADER_CONNECTION "Connection" #define HEADER_HOST "Host" #define HEADER_DATE "Date" - +#define HEADER_ACCEPT "Accept" #ifndef SAVE_STR #define SAVE_STR(str) ((str==0)?("(null)"):(str)) #endif +#define TRANSFER_ENCODING_CHUNKED "chunked" + +#define MAX_HEADER_SIZE 4256 +#define MAX_SOCKET_BUFFER_SIZE 4256 + /* Set Sleep function platform depended */ @@ -47,6 +54,8 @@ Set Sleep function platform depended #define system_sleep(seconds) sleep(seconds); #endif +typedef unsigned char byte_t; + /* string function to compare strings ignoring case Returns 1 if s1 equals s2 and 0 otherwise. @@ -54,6 +63,7 @@ Set Sleep function platform depended int strcmpigcase(const char *s1, const char *s2); + /* hpairnode_t represents a pair (key, value) pair. This is also a linked list. @@ -76,6 +86,11 @@ hpair_t* hpairnode_copy_deep(const hpair_t *src); void hpairnode_dump_deep(hpair_t *pair); void hpairnode_dump(hpair_t *pair); +typedef enum http_version { + HTTP_1_0, + HTTP_1_1 /* default */ +}http_version_t; + typedef enum hreq_method { HTTP_REQUEST_POST, @@ -95,40 +110,33 @@ typedef struct hurl hurl_t* hurl_new(const char* urlstr); void hurl_free(hurl_t *url); -/* - request object - */ -typedef struct hrequest -{ - char *method; - char *path; - char *spec; - hpair_t *query; - hpair_t *header; -}hrequest_t; -hrequest_t *hrequest_new_from_buffer(char *data); -void hrequest_free(hrequest_t *req); -/* response object */ +/* + DIME common stuff +*/ +#define DIME_VERSION_1 0x08 +#define DIME_FIRST_PACKAGE 0x04 +#define DIME_LAST_PACKAGE 0x02 +#define DIME_CHUNKED 0x01 +#define DIME_TYPE_URI 0x2 -typedef struct hresponse +typedef struct _DIME_PACKAGE { - char spec[10]; - int errcode; - char *desc; - hpair_t *header; - char *body; - long bodysize; -}hresponse_t; + char version; /* Specifies the version of the DIME message */ + char first_record; /* Specifies that this record is the first record of the message */ + char last_recored; /* Specifies that this record is the last record of the message */ + char chunked; /* Specifies that the contents of the message have been chunked */ + char type_t; /* Specifies the structure and format of the TYPE field */ + char *options; /* Contains any optional information used by a DIME parser */ + char *id; /* Contains a URI for uniquely identifying a DIME payload with any + additional padding; */ + char *type; /* Specifies the encoding for the record based on a type reference URI or a MIME media-type */ + int data_size; /* Specifies the length (in bytes) of the DATA */ + unsigned char* data; /* Contains the actual data payload for the record; + format of the data depends on the type specified for the record */ +}DIME_PACKAGE; -/* - PARAMS - buffer: The hole received data from socket. - */ -hresponse_t *hresponse_new_from_buffer(const char* buffer); -hresponse_t *hresponse_new(); -void hresponse_free(hresponse_t *res); /* logging stuff*/ typedef enum log_level diff --git a/nanohttp/nanohttp-reqres.h b/nanohttp/nanohttp-reqres.h new file mode 100755 index 0000000..0aaef72 --- /dev/null +++ b/nanohttp/nanohttp-reqres.h @@ -0,0 +1,73 @@ +/****************************************************************** + * $Id: nanohttp-reqres.h,v 1.1 2004/09/19 07:05:03 snowdrop Exp $ + * + * CSOAP Project: A http client/server library in C + * Copyright (C) 2003-2004 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: ferhatayaz@yahoo.com + ******************************************************************/ +#ifndef NANO_HTTP_REQRES_H +#define NANO_HTTP_REQRES_H + +#include + +/* + request object + */ +typedef struct hrequest +{ + char *method; + char *path; + char *spec; + hpair_t *query; + hpair_t *header; +}hrequest_t; + +hrequest_t *hrequest_new_from_buffer(char *data); +void hrequest_free(hrequest_t *req); + +/* response object */ +typedef struct hresponse +{ + char spec[10]; + int errcode; + char *desc; + hpair_t *header; + char *body; + long bodysize; + http_input_stream_t *in; +}hresponse_t; + +/* + PARAMS + buffer: The hole received data from socket. + */ +hresponse_t *hresponse_new_from_buffer(const char* buffer); +hresponse_t *hresponse_new_from_socket(hsocket_t sock); +hresponse_t *hresponse_new(); +void hresponse_free(hresponse_t *res); + + + +#endif + + + + + + diff --git a/nanohttp/nanohttp-server.c b/nanohttp/nanohttp-server.c index f6f2288..9fecc1a 100644 --- a/nanohttp/nanohttp-server.c +++ b/nanohttp/nanohttp-server.c @@ -1,5 +1,5 @@ /****************************************************************** -* $Id: nanohttp-server.c,v 1.24 2004/09/14 17:34:36 snowdrop Exp $ +* $Id: nanohttp-server.c,v 1.25 2004/09/19 07:05:03 snowdrop Exp $ * * CSOAP Project: A http client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -559,26 +559,27 @@ httpd_run () /* Wait for a socket to accept */ while (_httpd_run) { - /* zero and set file descriptior */ - FD_ZERO (&fds); - FD_SET (_httpd_socket, &fds); - - /* select socket descriptor */ - switch (select(_httpd_socket+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, &fds)) { - break; - } + /* zero and set file descriptior */ + FD_ZERO (&fds); + FD_SET (_httpd_socket, &fds); + + /* select socket descriptor */ + switch (select(_httpd_socket+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, &fds)) + { + break; + } } /* check signal status*/ @@ -601,14 +602,14 @@ httpd_run () } -char * +unsigned 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; + unsigned char *postdata = NULL; if (!strcmp (req->method, "POST")) { @@ -636,14 +637,14 @@ httpd_get_postdata (httpd_conn_t * conn, hrequest_t * req, long *received, postdata[0] = '\0'; return postdata; } - postdata = (char *) malloc (content_length + 1); + postdata = (unsigned 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) + (int)content_length, 1)>0) { *received = content_length; postdata[content_length] = '\0'; diff --git a/nanohttp/nanohttp-server.h b/nanohttp/nanohttp-server.h index d7ff39e..3170c3d 100644 --- a/nanohttp/nanohttp-server.h +++ b/nanohttp/nanohttp-server.h @@ -1,5 +1,5 @@ /****************************************************************** - * $Id: nanohttp-server.h,v 1.4 2004/09/01 14:09:44 snowdrop Exp $ + * $Id: nanohttp-server.h,v 1.5 2004/09/19 07:05:03 snowdrop Exp $ * * CSOAP Project: A http client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -27,7 +27,7 @@ #include #include - +#include #define NHTTPD_ARG_PORT "-NHTTPport" #define NHTTPD_ARG_TERMSIG "-NHTTPtsig" @@ -73,7 +73,7 @@ int httpd_send_header(httpd_conn_t *res, hpair_t *pair); -char *httpd_get_postdata(httpd_conn_t *conn, +unsigned char *httpd_get_postdata(httpd_conn_t *conn, hrequest_t *req, long *received, long max); #endif diff --git a/nanohttp/nanohttp-socket.c b/nanohttp/nanohttp-socket.c index c1699e8..718b96f 100644 --- a/nanohttp/nanohttp-socket.c +++ b/nanohttp/nanohttp-socket.c @@ -1,513 +1,490 @@ -/****************************************************************** -* $Id: nanohttp-socket.c,v 1.21 2004/09/14 15:50:54 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 -#include - - - - -#ifdef WIN32 - #include "wsockcompat.h" - #include - #include - -#ifndef __MINGW32__ - typedef int ssize_t; -#endif - -#else - #include -#endif - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef HAVE_SYS_TYPES_H -#include -#endif - -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#ifdef HAVE_ARPA_INET_H -#include -#endif - -#ifdef HAVE_NETDB_H -#include -#endif - -#ifdef HAVE_UNISTD_H -#include -#endif - -#include -#include - -/*-------------------------------------------------- -FUNCTION: hsocket_module_init -NOTE: This will be called from httpd_init() - for server and from httpc_init() for client -----------------------------------------------------*/ -int -hsocket_module_init () -{ -#ifdef WIN32 - struct WSAData info; - WSAStartup (MAKEWORD (2, 2), &info); - -#else /* */ - /* nothing to init for unix sockets */ -#endif /* */ - return 0; -} - -/*-------------------------------------------------- -FUNCTION: hsocket_module_destroy -----------------------------------------------------*/ -void -hsocket_module_destroy () -{ -#ifdef WIN32 - WSACleanup (); - -#else /* */ - /* nothing to destroy for unix sockets */ -#endif /* */ -} - - -/*-------------------------------------------------- -FUNCTION: hsocket_init -----------------------------------------------------*/ -int -hsocket_init (hsocket_t * sock) -{ - /* 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) -{ - hsocket_t sock; - char *ip; - struct sockaddr_in address; - struct hostent *host; - - sock = socket (AF_INET, SOCK_STREAM, 0); - if (sock <= 0) - return HSOCKET_CAN_NOT_CREATE; - - /* Get host data */ - host = gethostbyname (hostname); - if (host == NULL) - return HSOCKET_CAN_NOT_GET_HOSTNAME; - - ip = inet_ntoa (*(struct in_addr *) *host->h_addr_list); - address.sin_addr.s_addr = inet_addr (ip); - - /* set server addresss */ - address.sin_family = host->h_addrtype; - address.sin_port = htons (port); - /* 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_bind -----------------------------------------------------*/ -int -hsocket_bind (hsocket_t * dsock, int port) -{ - hsocket_t sock; - struct sockaddr_in addr; - - /* create socket */ - sock = socket (AF_INET, SOCK_STREAM, 0); - if (sock == -1) - { - log_error2 ("Can not create socket: '%s'", strerror (errno)); - return HSOCKET_CAN_NOT_CREATE; - } - /* bind socket */ - addr.sin_family = AF_INET; - addr.sin_port = htons (port); /* short, network byte order */ - addr.sin_addr.s_addr = INADDR_ANY; - memset (&(addr.sin_zero), '\0', 8); /* zero the rest of the - * struct */ - - if (bind (sock, (struct sockaddr *) &addr, sizeof (struct sockaddr)) == -1) - { - log_error2 ("Can not bind: '%s'", strerror (errno)); - return HSOCKET_CAN_NOT_BIND; - } - *dsock = sock; - return HSOCKET_OK; -} - - -/*---------------------------------------------------------- -FUNCTION: hsocket_accept -----------------------------------------------------------*/ -int hsocket_accept(hsocket_t sock, hsocket_t *dest) -{ - socklen_t asize; - hsocket_t sockfd; - struct sockaddr_in addr; - - asize = sizeof(struct sockaddr_in); -#ifdef WIN32 - while(1) - { - sockfd = accept(sock, (struct sockaddr *)&addr, &asize); - if (sockfd == INVALID_SOCKET) - { - if(WSAGetLastError()!=WSAEWOULDBLOCK) - return HSOCKET_CAN_NOT_ACCEPT; - } - else - { - break; - } - } -#else - sockfd = accept(sock, (struct sockaddr *)&addr, &asize); - if (sockfd == -1) { - return HSOCKET_CAN_NOT_ACCEPT; - } -#endif - log_verbose3("accept new socket (%d) from '%s'", sockfd, - SAVE_STR(((char*)inet_ntoa(addr.sin_addr))) ); - - *dest = sockfd; - return HSOCKET_OK; -} - -/*-------------------------------------------------- -FUNCTION: hsocket_listen -----------------------------------------------------*/ -int -hsocket_listen (hsocket_t sock, int n) -{ - if (listen (sock, n) == -1) - { - log_error2 ("Can not listen: '%s'", strerror (errno)); - return HSOCKET_CAN_NOT_LISTEN; - } - return HSOCKET_OK; -} - -/*-------------------------------------------------- -FUNCTION: hsocket_close -----------------------------------------------------*/ -void -hsocket_close (hsocket_t sock) -{ -#ifdef WIN32 - closesocket (sock); -#else - close (sock); -#endif -} - - -/*-------------------------------------------------- -FUNCTION: hsocket_send -----------------------------------------------------*/ -int -hsocket_nsend (hsocket_t sock, const char *buffer, int n) -{ - int size; - - size = send ((int) sock, buffer, n, 0); - if (size == -1) - return HSOCKET_CAN_NOT_SEND; - - return HSOCKET_OK; -} - -/*-------------------------------------------------- -FUNCTION: hsocket_send -----------------------------------------------------*/ -int -hsocket_send (hsocket_t sock, const char *buffer) -{ - return hsocket_nsend(sock, buffer, strlen(buffer)); -} - - -int -hsocket_read (hsocket_t sock, char *buffer, int total, int force) -{ - int status; - int totalRead; - - totalRead = 0; - - do - { - status = recv (sock, &buffer[totalRead], total - totalRead, 0); - if (!force) - { -#ifdef WIN32 - if (WSAGetLastError () != WSAEWOULDBLOCK) - { - return status; - } -#else - return status; -#endif - } - if (status > 0) - { - totalRead += status; - } - else - { -#ifdef WIN32 - if (WSAGetLastError () != WSAEWOULDBLOCK) - { - return status; - } -#else - return status; -#endif - } - if (totalRead >= total) - return 0; - } - while (1); -} - -/*-------------------------------------------------- -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; - int bufSize; - - if (*totalSize > 0) - { - bufSize = *totalSize; - } - else - { - bufSize = HSOCKET_MAX_BUFSIZE; - } - - *totalSize = 0; - - /* calculate first size for realloc */ - if (*buffer) - { - fsize = strlen (*buffer); - } - else - { - fsize = 0; - } - - do - { - - size = recv (sock, tmp, bufSize, 0); - bufSize = HSOCKET_MAX_BUFSIZE; - - if (size == -1) - { - log_error1 ("Error reading from socket"); - return HSOCKET_CAN_NOT_RECEIVE; - } - if (size == 0) - { - break; - } - *totalSize += size; - if (*buffer) - { - log_verbose2 ("reallocation %d bytes", *totalSize + fsize + 1); - *buffer = (char *) realloc ((char *) *buffer, - (*totalSize) + fsize + - HSOCKET_MAX_BUFSIZE); - strcat (*buffer, tmp); - } - else - { - *buffer = (char *) realloc (NULL, *totalSize + 1); - strcpy (*buffer, tmp); - } - - (*buffer)[*totalSize + fsize] = '\0'; - chunk++; - } - while (size > 0); - - 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"); - 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; -} - - - -/*-------------------------------------------------- -FUNCTION: hbufsocket_read -----------------------------------------------------*/ -int -hbufsocket_read (hbufsocket_t * bufsock, char *buffer, int size) -{ - int status; - int tmpsize; - - if (bufsock->bufsize - bufsock->cur >= size) - { - - log_verbose1 ("no need to read from socket"); - strncpy (buffer, &(bufsock->buffer[bufsock->cur]), size); - bufsock->cur += size; - return HSOCKET_OK; - - } - else - { - - tmpsize = bufsock->bufsize - bufsock->cur; - log_verbose2 ("tmpsize = %d", tmpsize); - - if (tmpsize > 0) - strncpy (buffer, &(bufsock->buffer[bufsock->cur]), tmpsize); - - size -= tmpsize; - - free (bufsock->buffer); - - status = hsocket_read (bufsock->sock, &buffer[tmpsize], size, 1); - if (status == size) - { - bufsock->buffer = (char *) malloc (size + 1); - strncpy (bufsock->buffer, &buffer[tmpsize], size); - bufsock->cur = size; - } - else - { - return status; - } - - return HSOCKET_OK; - } -} - -int -hsocket_makenonblock (hsocket_t sock) -{ -#ifdef WIN32 - unsigned long iMode; - iMode = HSOCKET_NONBLOCKMODE; - if (ioctlsocket (sock, FIONBIO, (u_long FAR *) & iMode) == INVALID_SOCKET) - { - log_error1 ("ioctlsocket error"); - return -1; - } -#else /* fcntl(sock, F_SETFL, O_NONBLOCK); */ -#endif - return HSOCKET_OK; -} - -#ifdef WIN32 - -struct tm * -localtime_r (const time_t * const timep, struct tm *p_tm) -{ - static struct tm *tmp; - tmp = localtime (timep); - if (tmp) - { - memcpy (p_tm, tmp, sizeof (struct tm)); - tmp = p_tm; - } - return tmp; -} - -#endif /* */ +/****************************************************************** +* $Id: nanohttp-socket.c,v 1.22 2004/09/19 07:05:03 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 +#include + +#ifdef WIN32 +#include "wsockcompat.h" +#include +#include + +#ifndef __MINGW32__ +typedef int ssize_t; +#endif + +#else +#include +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#include + +/*-------------------------------------------------- +FUNCTION: hsocket_module_init +NOTE: This will be called from httpd_init() + for server and from httpc_init() for client +----------------------------------------------------*/ +int +hsocket_module_init () +{ +#ifdef WIN32 + struct WSAData info; + WSAStartup (MAKEWORD (2, 2), &info); + +#else /* */ + /* nothing to init for unix sockets */ +#endif /* */ + return 0; +} + +/*-------------------------------------------------- +FUNCTION: hsocket_module_destroy +----------------------------------------------------*/ +void +hsocket_module_destroy () +{ +#ifdef WIN32 + WSACleanup (); + +#else /* */ + /* nothing to destroy for unix sockets */ +#endif /* */ +} + +/*-------------------------------------------------- +FUNCTION: hsocket_init +----------------------------------------------------*/ +int +hsocket_init (hsocket_t * sock) +{ + /* 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) +{ + hsocket_t sock; + char *ip; + struct sockaddr_in address; + struct hostent *host; + + sock = socket (AF_INET, SOCK_STREAM, 0); + if (sock <= 0) + return HSOCKET_CAN_NOT_CREATE; + + /* Get host data */ + host = gethostbyname (hostname); + if (host == NULL) + return HSOCKET_CAN_NOT_GET_HOSTNAME; + + ip = inet_ntoa (*(struct in_addr *) *host->h_addr_list); + address.sin_addr.s_addr = inet_addr (ip); + + /* set server addresss */ + address.sin_family = host->h_addrtype; + address.sin_port = htons (port); + + /* 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_bind +----------------------------------------------------*/ +int +hsocket_bind (hsocket_t * dsock, int port) +{ + hsocket_t sock; + struct sockaddr_in addr; + + /* create socket */ + sock = socket (AF_INET, SOCK_STREAM, 0); + if (sock == -1) + { + log_error2 ("Can not create socket: '%s'", strerror (errno)); + return HSOCKET_CAN_NOT_CREATE; + } + /* bind socket */ + addr.sin_family = AF_INET; + addr.sin_port = htons (port); /* short, network byte order */ + addr.sin_addr.s_addr = INADDR_ANY; + memset (&(addr.sin_zero), '\0', 8); /* zero the rest of the + * struct */ + + if (bind (sock, (struct sockaddr *) &addr, sizeof (struct sockaddr)) == -1) + { + log_error2 ("Can not bind: '%s'", strerror (errno)); + return HSOCKET_CAN_NOT_BIND; + } + *dsock = sock; + return HSOCKET_OK; +} + +/*---------------------------------------------------------- +FUNCTION: hsocket_accept +----------------------------------------------------------*/ +int +hsocket_accept (hsocket_t sock, hsocket_t * dest) +{ + socklen_t asize; + hsocket_t sockfd; + struct sockaddr_in addr; + + asize = sizeof (struct sockaddr_in); +#ifdef WIN32 + while (1) + { + sockfd = accept (sock, (struct sockaddr *) &addr, &asize); + if (sockfd == INVALID_SOCKET) + { + if (WSAGetLastError () != WSAEWOULDBLOCK) + return HSOCKET_CAN_NOT_ACCEPT; + } + else + { + break; + } + } +#else + sockfd = accept (sock, (struct sockaddr *) &addr, &asize); + if (sockfd == -1) + { + return HSOCKET_CAN_NOT_ACCEPT; + } +#endif + log_verbose3 ("accept new socket (%d) from '%s'", sockfd, + SAVE_STR (((char *) inet_ntoa (addr.sin_addr)))); + + *dest = sockfd; + return HSOCKET_OK; +} + +/*-------------------------------------------------- +FUNCTION: hsocket_listen +----------------------------------------------------*/ +int +hsocket_listen (hsocket_t sock, int n) +{ + if (listen (sock, n) == -1) + { + log_error2 ("Can not listen: '%s'", strerror (errno)); + return HSOCKET_CAN_NOT_LISTEN; + } + return HSOCKET_OK; +} + +/*-------------------------------------------------- +FUNCTION: hsocket_close +----------------------------------------------------*/ +void +hsocket_close (hsocket_t sock) +{ +#ifdef WIN32 + closesocket (sock); +#else + close (sock); +#endif +} + +/*-------------------------------------------------- +FUNCTION: hsocket_send +----------------------------------------------------*/ +int +hsocket_nsend (hsocket_t sock, const unsigned char *bytes, int n) +{ + int size; + + size = send ((int) sock, bytes, n, 0); + if (size == -1) + return HSOCKET_CAN_NOT_SEND; + + return HSOCKET_OK; +} + +/*-------------------------------------------------- +FUNCTION: hsocket_send +----------------------------------------------------*/ +int +hsocket_send (hsocket_t sock, const char *str) +{ + return hsocket_nsend (sock, str, strlen (str)); +} + +/* + return: -1 is error. read bytes otherwise +*/ +int +hsocket_read (hsocket_t sock, unsigned char *buffer, int total, int force) +{ + int status; + int totalRead; + + totalRead = 0; + + do + { + status = recv (sock, &buffer[totalRead], total - totalRead, 0); + +#ifdef WIN32 + if (status == INVALID_SOCKET) + if (WSAGetLastError () == WSAEWOULDBLOCK) + continue; + else + return -1; +#else + if (status == -1) + return -1; +#endif + + if (!force) + return status; + + totalRead += status; + + if (totalRead == total) + return totalRead; + } + while (1); +} + +/*-------------------------------------------------- +FUNCTION: hsocket_recv +----------------------------------------------------*/ +int +hsocket_recv (hsocket_t sock, unsigned char **buffer, int *totalSize) +{ + ssize_t size; + int chunk = 1; + char tmp[HSOCKET_MAX_BUFSIZE + 1]; + int fsize; + int bufSize; + + if (*totalSize > 0) + bufSize = *totalSize; + else + bufSize = HSOCKET_MAX_BUFSIZE; + + *totalSize = 0; + + /* calculate first size for realloc */ + if (*buffer) + fsize = strlen (*buffer); + else + fsize = 0; + + do + { + size = recv (sock, tmp, bufSize, 0); + bufSize = HSOCKET_MAX_BUFSIZE; + + if (size == -1) + { + log_error1 ("Error reading from socket"); + return HSOCKET_CAN_NOT_RECEIVE; + } + + if (size == 0) + { + break; + } + *totalSize += size; + if (*buffer) + { + log_verbose2 ("reallocation %d bytes", *totalSize + fsize + 1); + *buffer = (char *) realloc ((char *) *buffer, + (*totalSize) + fsize + HSOCKET_MAX_BUFSIZE); + strcat (*buffer, tmp); + } + else + { + *buffer = (char *) realloc (NULL, *totalSize + 1); + strcpy (*buffer, tmp); + } + + (*buffer)[*totalSize + fsize] = '\0'; + chunk++; + } while (size > 0); + + 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"); + 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; +} + +/*-------------------------------------------------- +FUNCTION: hbufsocket_read +----------------------------------------------------*/ +int +hbufsocket_read (hbufsocket_t * bufsock, char *buffer, int size) +{ + int status; + int tmpsize; + + if (bufsock->bufsize - bufsock->cur >= size) + { + + /* no need to read from socket*/ + strncpy (buffer, &(bufsock->buffer[bufsock->cur]), size); + bufsock->cur += size; + return HSOCKET_OK; + + } + else + { + + tmpsize = bufsock->bufsize - bufsock->cur; + log_verbose5 ("tmpsize=%d, bufsock->bufsize=%d, bufsock->cur=%d, size=%d", + tmpsize, bufsock->bufsize, bufsock->cur, size); + + if (tmpsize > 0) + strncpy (buffer, &(bufsock->buffer[bufsock->cur]), tmpsize); + + size -= tmpsize; + + free (bufsock->buffer); + + status = hsocket_read (bufsock->sock, &buffer[tmpsize], size, 1); + log_verbose3("hsocket_read(): size=%d,status=%d", size, status); + if (status == size) + { + bufsock->buffer = (char *) malloc (size + 1); + strncpy (bufsock->buffer, &buffer[tmpsize], size); + bufsock->cur = size; + bufsock->bufsize = size; + } + else + { + return status; + } + + return HSOCKET_OK; + } +} + +int +hsocket_makenonblock (hsocket_t sock) +{ +#ifdef WIN32 + unsigned long iMode; + iMode = HSOCKET_NONBLOCKMODE; + if (ioctlsocket (sock, FIONBIO, (u_long FAR *) & iMode) == INVALID_SOCKET) + { + log_error1 ("ioctlsocket error"); + return -1; + } +#else /* fcntl(sock, F_SETFL, O_NONBLOCK); */ +#endif + return HSOCKET_OK; +} + +#ifdef WIN32 + +struct tm * +localtime_r (const time_t * const timep, struct tm *p_tm) +{ + static struct tm *tmp; + tmp = localtime (timep); + if (tmp) + { + memcpy (p_tm, tmp, sizeof (struct tm)); + tmp = p_tm; + } + return tmp; +} + +#endif /* */ diff --git a/nanohttp/nanohttp-socket.h b/nanohttp/nanohttp-socket.h index 117a5b2..48d2a0b 100644 --- a/nanohttp/nanohttp-socket.h +++ b/nanohttp/nanohttp-socket.h @@ -1,5 +1,5 @@ /****************************************************************** - * $Id: nanohttp-socket.h,v 1.11 2004/09/14 13:23:10 snowdrop Exp $ + * $Id: nanohttp-socket.h,v 1.12 2004/09/19 07:05:03 snowdrop Exp $ * * CSOAP Project: A http client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -118,7 +118,7 @@ int hsocket_accept(hsocket_t sock, hsocket_t *dest); Returns 0 if success >0 if fail */ -int hsocket_nsend(hsocket_t sock, const char* buffer, int n); +int hsocket_nsend(hsocket_t sock, const unsigned char* buffer, int n); /* hsocket_send @@ -126,7 +126,7 @@ int hsocket_nsend(hsocket_t sock, const char* buffer, int n); Returns 0 if success >0 if fail */ -int hsocket_send(hsocket_t sock, const char* buffer); +int hsocket_send(hsocket_t sock, const char* str); /* @@ -161,7 +161,7 @@ int hsocket_send(hsocket_t sock, const char* buffer); Returns 0 if success >0 if fail */ -int hsocket_recv(hsocket_t sock, char** buffer, int *size); +int hsocket_recv(hsocket_t sock, unsigned char** buffer, int *size); int hsocket_recv_limit(hsocket_t sock, char** buffer, const char* delim, char **rest, @@ -173,7 +173,7 @@ int hsocket_recv_limit(hsocket_t sock, char** buffer, int hsocket_recv_cb(hsocket_t sock, hsocket_recv_callback cb, void *userdata); -int hsocket_read(hsocket_t sock, char* buffer, int total, int force); +int hsocket_read(hsocket_t sock, unsigned char* buffer, int total, int force); /* ======================================== */ diff --git a/nanohttp/nanohttp-stream.c b/nanohttp/nanohttp-stream.c new file mode 100755 index 0000000..8eb31d6 --- /dev/null +++ b/nanohttp/nanohttp-stream.c @@ -0,0 +1,292 @@ +/****************************************************************** +* $Id: nanohttp-stream.c,v 1.1 2004/09/19 07:05:03 snowdrop Exp $ +* +* CSOAP Project: A http client/server library in C +* Copyright (C) 2003-2004 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: ferhatayaz@yahoo.com +******************************************************************/ + +#define STREAM_INVALID -1 +#define STREAM_INVALID_TYPE -2 +#define STREAM_SOCKET_ERROR -3 +#define STREAM_NO_CHUNK_SIZE -4 + +#include + +static +int _http_stream_is_content_length(hpair_t *header) +{ + return + hpairnode_get_ignore_case(header, HEADER_CONTENT_LENGTH) != NULL; +} + +static +int _http_stream_is_chunked(hpair_t *header) +{ + char *chunked; + chunked = hpairnode_get_ignore_case(header, HEADER_TRANSFER_ENCODING); + if (chunked != NULL) + { + if (!strcmp(chunked, TRANSFER_ENCODING_CHUNKED)) + { + return 1; + } + } + + return 0; +} + +/** + Creates a new input stream. +*/ +http_input_stream_t *http_input_stream_new(hsocket_t sock, hpair_t *header) +{ + http_input_stream_t *result; + char *content_length; + char *chunked; + + /* Paranoya check */ + if (header == NULL) + return NULL; + + /* Create object */ + result = (http_input_stream_t*)malloc(sizeof(http_input_stream_t)); + result->sock = sock; + + /* Find connection type */ + + /* Check if Content-type */ + if (_http_stream_is_content_length(header)) + { + log_verbose1("Stream transfer with 'Content-length'"); + content_length = hpairnode_get_ignore_case(header, HEADER_CONTENT_LENGTH); + result->content_length = atoi(content_length); + result->received = 0; + result->type = HTTP_TRANSFER_CONTENT_LENGTH; + } + /* Check if Chunked */ + else if (_http_stream_is_chunked(header)) + { + log_verbose1("Stream transfer with 'chunked'"); + result->type = HTTP_TRANSFER_CONTENT_CHUNKED; + result->chunk_size = -1; + result->received = -1; + } + /* Assume connection close */ + else + { + log_verbose1("Stream transfer with 'Connection: close'"); + result->type = HTTP_TRANSFER_CONNECTION_CLOSE; + } + + return result; +} + + +/** + Free input stream +*/ +void http_input_stream_free(http_input_stream_t *stream) +{ + free(stream); +} + +static +int _http_input_stream_is_content_length_ready( + http_input_stream_t *stream) +{ + return (stream->content_length > stream->received); +} + +static +int _http_input_stream_is_chunked_ready( + http_input_stream_t *stream) +{ + return stream->chunk_size != 0; + +} + +static +int _http_input_stream_is_connection_closed_ready( + http_input_stream_t *stream) +{ +/* TODO (#1#): implement */ +} + +static +int _http_input_stream_content_length_read( + http_input_stream_t *stream, byte_t *dest, size_t size) +{ + int status; + + /* check limit */ + if (stream->content_length - stream->received < size) + size = stream->content_length - stream->received; + + /* read from socket */ + status = hsocket_read(stream->sock, dest, size, 1); + if (status == -1) + return STREAM_SOCKET_ERROR; + + stream->received += status; + return status; +} + +static +int _http_input_stream_chunked_read_chunk_size( + http_input_stream_t *stream) +{ + char chunk[25]; + int chunk_size, status, i = 0; + + while (1) + { + status = hsocket_read(stream->sock, &(chunk[i]), 1, 1); + + if (status == -1) + return STREAM_SOCKET_ERROR; + + if (chunk[i] == '\r' || chunk[i] == ';') + { + chunk[i] = '\0'; + } + else if (chunk[i] == '\n') + { + chunk[i] = '\0'; /* double check*/ + chunk_size = strtol(chunk, (char **) NULL, 16); /* hex to dec */ + log_debug3("chunk_size: '%s' as dec: '%d'", chunk, chunk_size); + return chunk_size; + } + + if (i == 24) + return STREAM_NO_CHUNK_SIZE; + else + i++; + } + + /* this should never happens */ + return STREAM_NO_CHUNK_SIZE; +} + +static +int _http_input_stream_chunked_read( + http_input_stream_t *stream, byte_t *dest, size_t size) +{ + int status; + int remain, read=0; + + while (size > 0) + { + remain = stream->chunk_size - stream->received ; + + if (remain == 0) + { + /* receive new chunk size */ + stream->chunk_size = + _http_input_stream_chunked_read_chunk_size(stream); + + if (stream->chunk_size < 0) + { + /* TODO (#1#): set error flag */ + return stream->chunk_size; + } + else if (stream->chunk_size == 0) + { + return read; + } + remain = stream->chunk_size; + } + + /* show remaining chunk size in socket */ + if (remain < size) + { + /* read from socket */ + status = hsocket_read(stream->sock, &(dest[read]), remain, 1); + if (status == -1) + return STREAM_SOCKET_ERROR; + + } + else + { + /* read from socket */ + status = hsocket_read(stream->sock, &(dest[read]), size, 1); + if (status == -1) + return STREAM_SOCKET_ERROR; + } + + read += status; + size -= status; + stream->received += status; + } +} + +static +int _http_input_stream_connection_closed_read( + http_input_stream_t *stream, byte_t *dest, size_t size) +{ +/* TODO (#1#): implement */ + return 0; +} + +/** + Returns the actual status of the stream. +*/ +int http_input_stream_is_ready(http_input_stream_t *stream) +{ + /* paranoya check */ + if (stream == NULL) + return 0; + + switch (stream->type) + { + case HTTP_TRANSFER_CONTENT_LENGTH: + return _http_input_stream_is_content_length_ready(stream); + case HTTP_TRANSFER_CONTENT_CHUNKED: + return _http_input_stream_is_chunked_ready(stream); + case HTTP_TRANSFER_CONNECTION_CLOSE: + return _http_input_stream_is_connection_closed_ready(stream); + default: + return 0; + } +} + +/** + Returns the actual read bytes + <0 on error +*/ +int http_input_stream_read(http_input_stream_t *stream, + byte_t *dest, size_t size) +{ + /* paranoya check */ + if (stream == NULL) + return STREAM_INVALID; + + switch (stream->type) + { + case HTTP_TRANSFER_CONTENT_LENGTH: + return _http_input_stream_content_length_read(stream, dest, size); + case HTTP_TRANSFER_CONTENT_CHUNKED: + return _http_input_stream_chunked_read(stream, dest, size); + case HTTP_TRANSFER_CONNECTION_CLOSE: + return _http_input_stream_connection_closed_read(stream, dest, size); + default: + return STREAM_INVALID_TYPE; + } +} + diff --git a/nanohttp/nanohttp-stream.h b/nanohttp/nanohttp-stream.h new file mode 100755 index 0000000..edbf371 --- /dev/null +++ b/nanohttp/nanohttp-stream.h @@ -0,0 +1,80 @@ +/****************************************************************** + * $Id: nanohttp-stream.h,v 1.1 2004/09/19 07:05:03 snowdrop Exp $ + * + * CSOAP Project: A http client/server library in C + * Copyright (C) 2003-2004 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: ferhatayaz@yahoo.com + ******************************************************************/ +#ifndef NANO_HTTP_STREAM_H +#define NANO_HTTP_STREAM_H + +#include +#include + +/** + Supported transfer types +*/ +typedef enum http_transfer_type +{ + HTTP_TRANSFER_CONTENT_LENGTH, + HTTP_TRANSFER_CONTENT_CHUNKED, + HTTP_TRANSFER_CONNECTION_CLOSE +}http_transfer_type_t; + +/** + HTTP INPUT STREAM +*/ +typedef struct http_input_stream +{ + hsocket_t sock; + http_transfer_type_t type; + size_t received; + size_t content_length; + size_t chunk_size; +}http_input_stream_t; + + +/** + Creates a new input stream. +*/ +http_input_stream_t *http_input_stream_new(hsocket_t sock, hpair_t *header); + +/** + Free input stream +*/ +void http_input_stream_free(http_input_stream_t *stream); + +/** + Returns the actual status of the stream. +*/ +int http_input_stream_is_ready(http_input_stream_t *stream); + +/** + Returns the actual read bytes +*/ +int http_input_stream_read(http_input_stream_t *stream, + byte_t *dest, size_t size); + +#endif + + + + + + -- cgit v1.1-32-gdbae