From 15c050ac3a39c9022268aa72770dc94956088615 Mon Sep 17 00:00:00 2001 From: snowdrop Date: Tue, 16 Dec 2003 13:16:11 +0000 Subject: added chunked transfer encoding --- nanohttp/nanohttp-client.c | 188 ++++++++++++++++++++++++++++++++++++++++----- nanohttp/nanohttp-common.c | 31 ++++++-- nanohttp/nanohttp-common.h | 5 +- nanohttp/nanohttp-socket.c | 78 ++++++++++++++++++- nanohttp/nanohttp-socket.h | 19 ++++- 5 files changed, 292 insertions(+), 29 deletions(-) diff --git a/nanohttp/nanohttp-client.c b/nanohttp/nanohttp-client.c index 72af32e..8f3f37b 100644 --- a/nanohttp/nanohttp-client.c +++ b/nanohttp/nanohttp-client.c @@ -1,5 +1,5 @@ /****************************************************************** - * $Id: nanohttp-client.c,v 1.1 2003/12/11 14:51:04 snowdrop Exp $ + * $Id: nanohttp-client.c,v 1.2 2003/12/16 13:16:11 snowdrop Exp $ * * CSOAP Project: A http client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -374,7 +374,6 @@ int httpc_recv_cb_callback(hsocket_t sock, char *buffer, return 1; } - /*-------------------------------------------------- FUNCTION: httpc_get_cb ----------------------------------------------------*/ @@ -392,6 +391,24 @@ int httpc_get_cb(httpc_conn_t *conn, const char *urlstr, int restsize; httpc_cb_userdata_t cbdata; + /* content-length */ + char *content_length_str; + long content_length; + long remain_length; + int counter; + int recvSize; + char readBuf[HSOCKET_MAX_BUFSIZE]; + + /* chunked encoding */ + char *transfer_encoding; + char *chunk_buffer; + int chunk_size, cs; + hbufsocket_t bufsock; + char tmpch; + char chunk_size_str[25]; + int chunk_size_cur; + char chunk_ch[2]; + if (conn == NULL) { log_error1("Connection object is NULL"); return 1; @@ -440,40 +457,175 @@ int httpc_get_cb(httpc_conn_t *conn, const char *urlstr, return 5; } - /* Receive Response */ + /* Receive Response incl. header */ 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; + return 6; } res = hresponse_new(response); if (res == NULL) { log_error2("Can't create response (url:'%s')", urlstr); - return 6; + return 7; } /* 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; + /* ================================================= */ + /* Retreive with content-length */ + /* ================================================= */ - hsocket_recv_cb(conn->sock, httpc_recv_cb_callback, &cbdata); + /* Check if server communicates with content-length */ + content_length_str = + hpairnode_get(res->header, HEADER_CONTENT_LENGTH); - return 0; + if (content_length_str != NULL) { + + log_debug1("Server communicates with content-length!"); + + /* Invoke callback for rest */ + if (restsize > 0) + cb(0, conn, userdata, restsize, rest); + + /* content length */ + content_length = atol(content_length_str); + + counter = 1; + remain_length = content_length - restsize; + while (remain_length > 0) { + if (remain_length >= HSOCKET_MAX_BUFSIZE) { + recvSize = HSOCKET_MAX_BUFSIZE; + } else { + recvSize = remain_length; + } + + if (hsocket_read(conn->sock, readBuf, recvSize)) { + log_error1("Can not read from socket!"); + return 9; + } else { + cb(counter++, conn, userdata, recvSize, readBuf); + } + + remain_length -= HSOCKET_MAX_BUFSIZE; + + } /* while */ + + /* rest and response are no longer required */ + free(rest); + free(response); + + return 0; + + } /* if content length */ + + + /* ================================================= */ + /* Retreive with chunked encoding */ + /* ================================================= */ + + /* Check if server communicates with chunked encoding */ + transfer_encoding = + hpairnode_get(res->header, HEADER_TRANSFER_ENCODING); + if (transfer_encoding != NULL && + !strcmp(transfer_encoding, "chunked")) { + + log_debug1("Server communicates with chunked encoding !"); + + /* read chunk size */ + /* + strncpy(chunk_size_str, rest, 15); + chunk_size_cur = 0; + cs = 0; + while (1) { + + chunk_size_str[chunk_size_cur] = rest[cs++]; + + if (chunk_size_str[chunk_size_cur] == '\n') { + chunk_size_str[chunk_size_cur] = '\0'; + break; + } + + if (chunk_size_str[chunk_size_cur] != '\r' + && chunk_size_str[chunk_size_cur] != ';') { + chunk_size_cur++; + } + + if (chunk_size_cur > 15) { + log_error1("Can not parse chunk size!"); + return 10; + } + + } + + chunk_size = strtol(chunk_size_str,(char**)NULL, 16); + + log_debug3("chunk_size: '%s' as dec: '%d'", + chunk_size_str, chunk_size); + */ + + /* initialize buffered socket */ + bufsock.sock = conn->sock; + bufsock.cur = 0; + bufsock.buffer = rest; + bufsock.bufsize = restsize; + + while (chunk_size > 0) { + + /* read chunk size */ + 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; + } + + if (chunk_size_str[chunk_size_cur] == '\n') { + chunk_size_str[chunk_size_cur] = '\0'; + break; + } + + if (chunk_size_str[chunk_size_cur] != '\r' + && chunk_size_str[chunk_size_cur] != ';') { + chunk_size_cur++; + } + + } /* while (1) */ + + chunk_size = strtol(chunk_size_str,(char**)NULL, 16); /* hex to dec */ + log_debug3("chunk_size: '%s' as dec: '%d'", + chunk_size_str, chunk_size); + + if (chunk_size <= 0) break; + + chunk_buffer = (char*)malloc(chunk_size); + if (hbufsocket_read(&bufsock, chunk_buffer, chunk_size)) { + log_error1("Can not read from socket"); + return 9; + } + cb(counter++, conn, userdata, chunk_size, chunk_buffer); + free(chunk_buffer); + + } /* while (chunk_size > 0) + + /* rest and response are no longer required */ + free(rest); + free(response); + + return 0; + + } /* if transfer_encodig */ + + + log_error1("Unknown server response retreive type!"); + + return 1; } diff --git a/nanohttp/nanohttp-common.c b/nanohttp/nanohttp-common.c index 9efe0ac..bb4cde9 100644 --- a/nanohttp/nanohttp-common.c +++ b/nanohttp/nanohttp-common.c @@ -1,5 +1,5 @@ /****************************************************************** - * $Id: nanohttp-common.c,v 1.1 2003/12/11 14:51:04 snowdrop Exp $ + * $Id: nanohttp-common.c,v 1.2 2003/12/16 13:16:13 snowdrop Exp $ * * CSOAP Project: A http client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -116,7 +116,8 @@ hpair_t *hpairnode_parse(const char *str, const char *delim, hpair_t *next) { hpair_t *pair; char *key, *value; - + int c; + pair = (hpair_t*)malloc(sizeof(hpair_t)); pair->key = ""; pair->value = ""; @@ -130,8 +131,9 @@ hpair_t *hpairnode_parse(const char *str, const char *delim, hpair_t *next) } if (value != NULL) { - pair->value = (char*)malloc(strlen(value)+1); - strcpy(pair->value, value); + for (c=0;value[c]==' ';c++); /* skip white space */ + pair->value = (char*)malloc(strlen(&value[c])+1); + strcpy(pair->value, &value[c]); } return pair; @@ -148,6 +150,25 @@ void hpairnode_free(hpair_t *pair) } +char *hpairnode_get(hpair_t *pair, const char* key) +{ + if (key == NULL) { + log_error1("key is NULL"); + return NULL; + } + + while (pair != NULL) { + if (pair->key != NULL) { + if (!strcmp(pair->key, key)) { + return pair->value; + } + } + pair = pair->next; + } + + return NULL; +} + static void hurl_dump(const hurl_t *url) { @@ -338,7 +359,7 @@ hresponse_t *hresponse_new(const char* buffer) } str[strlen(str)-1] = '\0'; - res->header = hpairnode_parse(str, ": ", res->header); + res->header = hpairnode_parse(str, ":", res->header); } /* *** Save body *** */ diff --git a/nanohttp/nanohttp-common.h b/nanohttp/nanohttp-common.h index d3bb702..65e8167 100644 --- a/nanohttp/nanohttp-common.h +++ b/nanohttp/nanohttp-common.h @@ -1,5 +1,5 @@ /****************************************************************** - * $Id: nanohttp-common.h,v 1.1 2003/12/11 14:51:04 snowdrop Exp $ + * $Id: nanohttp-common.h,v 1.2 2003/12/16 13:16:14 snowdrop Exp $ * * CSOAP Project: A http client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -27,6 +27,7 @@ #define HEADER_CONTENT_LENGTH "Content-Length" #define HEADER_CONTENT_TYPE "Content-Type" +#define HEADER_TRANSFER_ENCODING "Transfer-Encoding" #define HEADER_HOST "Host" #define HEADER_DATE "Date" @@ -50,7 +51,7 @@ struct hpair hpair_t *hpairnode_new(const char* key, const char* value, hpair_t* next); void hpairnode_free(hpair_t *pair); - +char *hpairnode_get(hpair_t *pair, const char* key); typedef enum hreq_method diff --git a/nanohttp/nanohttp-socket.c b/nanohttp/nanohttp-socket.c index 1a9742b..d465b8e 100644 --- a/nanohttp/nanohttp-socket.c +++ b/nanohttp/nanohttp-socket.c @@ -1,5 +1,5 @@ /****************************************************************** - * $Id: nanohttp-socket.c,v 1.1 2003/12/11 14:51:04 snowdrop Exp $ + * $Id: nanohttp-socket.c,v 1.2 2003/12/16 13:16:14 snowdrop Exp $ * * CSOAP Project: A http client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -234,6 +234,25 @@ int hsocket_recv_limit(hsocket_t sock, char** buffer, return HSOCKET_OK; } +int hsocket_read(hsocket_t sock, char* buffer, int total) +{ + int status; + int totalRead; + + totalRead = 0; + + do { + status = recv(sock, &buffer[totalRead], total - totalRead, 0); + if (status > 0) { + totalRead += status; + } else { + return status; + } + if (totalRead >= total) + return 0; + } while (1); +} + /*-------------------------------------------------- FUNCTION: hsocket_recv ----------------------------------------------------*/ @@ -243,6 +262,13 @@ int hsocket_recv(hsocket_t sock, char** buffer, int *totalSize) 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; @@ -255,7 +281,8 @@ int hsocket_recv(hsocket_t sock, char** buffer, int *totalSize) do { - size = recv(sock, tmp, HSOCKET_MAX_BUFSIZE, 0); + size = recv(sock, tmp, bufSize, 0); + bufSize = HSOCKET_MAX_BUFSIZE; if (size == -1) { log_error1("Error reading from socket\n"); @@ -269,7 +296,8 @@ int hsocket_recv(hsocket_t sock, char** buffer, int *totalSize) *totalSize += size; if (*buffer) { log_debug2("reallocation %d bytes",*totalSize+fsize+1); - *buffer = (char*)realloc((char*)*buffer, (*totalSize)+fsize+HSOCKET_MAX_BUFSIZE); + *buffer = (char*)realloc((char*)*buffer, + (*totalSize)+fsize+HSOCKET_MAX_BUFSIZE); strcat(*buffer, tmp); } else { log_debug1("Allocating"); @@ -322,3 +350,47 @@ int hsocket_recv_cb(hsocket_t sock, +/*-------------------------------------------------- + FUNCTION: hbufsocket_read +----------------------------------------------------*/ +int hbufsocket_read(hbufsocket_t *bufsock, char *buffer, int size) +{ + int status; + int tmpsize; + + if (bufsock->bufsize - bufsock->cur >= size) { + + log_debug1("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_debug2("tmpsize = %d", tmpsize); + + if (tmpsize > 0) + strncpy(buffer, &(bufsock->buffer[bufsock->cur]), tmpsize); + + size -= tmpsize; + + free(bufsock->buffer); + status = recv(bufsock->sock, bufsock->buffer, size, 0); + if (status > 0) { + bufsock->bufsize = size; + bufsock->cur = size; + strncpy(&buffer[tmpsize], bufsock->buffer, size); + } + + return HSOCKET_OK; + } +} + + + + + + + + diff --git a/nanohttp/nanohttp-socket.h b/nanohttp/nanohttp-socket.h index 92e92e2..901876f 100644 --- a/nanohttp/nanohttp-socket.h +++ b/nanohttp/nanohttp-socket.h @@ -1,5 +1,5 @@ /****************************************************************** - * $Id: nanohttp-socket.h,v 1.1 2003/12/11 14:51:04 snowdrop Exp $ + * $Id: nanohttp-socket.h,v 1.2 2003/12/16 13:16:14 snowdrop Exp $ * * CSOAP Project: A http client/server library in C * Copyright (C) 2003 Ferhat Ayaz @@ -124,6 +124,23 @@ 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); + + +/* ======================================== */ +/* Buffered socket */ +/* ======================================== */ +typedef struct _bufsocket +{ + hsocket_t sock; + char *buffer; + int bufsize; + int cur; +}hbufsocket_t; + + +int hbufsocket_read(hbufsocket_t *bufsock, char *buffer, int size); + #endif -- cgit v1.1-32-gdbae