From: Mohamed Abbas <mab...@linux.intel.com> Add basic http response parsing, iclude header and basic body. It also add user to receive notification on header line and body arrival. --- gweb/gweb.c | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 206 insertions(+), 2 deletions(-)
diff --git a/gweb/gweb.c b/gweb/gweb.c index 39f8ecf..6280c89 100644 --- a/gweb/gweb.c +++ b/gweb/gweb.c @@ -35,6 +35,9 @@ #include "gresolv.h" #include "gweb.h" +#define WEB_FLAG_HEADER_READY (0x1) +#define WEB_FLAG_DOWNLOAD_DONE (0x2) + struct web_session { GWeb *web; @@ -49,6 +52,13 @@ struct web_session { guint resolv_action; char *request; + GByteArray *line; + + long int total_len; + long int content_len; + size_t http_status; + + GWebReceivedFunc received_func; GWebResultFunc result_func; gpointer result_data; }; @@ -58,6 +68,7 @@ struct _GWeb { guint next_query_id; + gboolean send_header; int index; GList *session_list; @@ -67,6 +78,19 @@ struct _GWeb { gpointer debug_data; }; +static inline void set_flag(struct web_session *session, unsigned long bit) +{ + session->flags |= bit; +} + +static gboolean is_set(struct web_session *session, unsigned long bit) +{ + if (session->flags & bit) + return TRUE; + + return FALSE; +} + static inline void debug(GWeb *web, const char *format, ...) { char str[256]; @@ -101,6 +125,7 @@ static void free_session(struct web_session *session) if (session->transport_channel != NULL) g_io_channel_unref(session->transport_channel); + g_byte_array_free(session->line, TRUE); g_free(session->host); g_free(session->address); g_free(session); @@ -170,6 +195,12 @@ void g_web_unref(GWeb *web) g_free(web); } +void g_web_allow_header(GWeb *web, gboolean allow) +{ + + web->send_header = allow; +} + void g_web_set_debug(GWeb *web, GWebDebugFunc func, gpointer user_data) { if (web == NULL) @@ -191,12 +222,163 @@ gboolean g_web_add_nameserver(GWeb *web, const char *address) return TRUE; } +static void init_download_data(struct web_session *session) +{ + + session->http_status = 0; + session->total_len = 0; + session->content_len = -1; + + session->flags = 0; +} + +static int append_to_line(struct web_session *session, + unsigned char *buf, int len) +{ + g_byte_array_append(session->line, buf, len); + + return 0; +} + +static gboolean send_client_payload(struct web_session *session, + unsigned char *buf, int len) +{ + if (session->received_func != NULL) + return session->received_func(buf, len, G_WEB_DATA_BODY, + session->result_data); + + return TRUE; +} + +static gboolean send_client_header_line(struct web_session *session, + unsigned char *buf, int len) +{ + if (session->web->send_header == TRUE && + session->received_func != NULL) + return session->received_func(buf, len, G_WEB_DATA_HEADER, + session->result_data); + + return TRUE; +} + +static int decode_header(struct web_session *session, + unsigned char *buf, int len) +{ + unsigned char *ptr, *end_line; + int line_len; + int err; + + ptr = buf; + while (len > 0) { + end_line = memchr(ptr, '\n', len); + if (end_line == NULL) { + if (append_to_line(session, ptr, len) < 0) + return -EXFULL; + return 0; + } + + line_len = end_line - ptr; + line_len += 1; + + if (append_to_line(session, ptr, line_len) < 0) + return -EXFULL; + + if (send_client_header_line(session, session->line->data, + len) == FALSE) + return -1; + + /* we have full header line append \0 and process line */ + g_byte_array_append(session->line, (unsigned char *)"\0", 1); + + if (session->line->data[0] == '\r' || + session->line->data[0] == '\n') { + /* empty line http header is done */ + session->line->len = 0; + + set_flag(session, WEB_FLAG_HEADER_READY); + debug(session->web, "content len:%lu http status%lu", + session->content_len, + session->http_status); + + if (session->http_status != 0) + return (end_line - buf) + 1; + else + return -1; + } + /* first line should be http status */ + if (session->http_status == 0) { + + err = sscanf((char *)session->line->data, + "HTTP/1.%*d %u", + &session->http_status); + if (err != 1) { + debug(session->web, "error status %lu", + session->http_status); + return -1; + } + } else if (session->content_len == -1 && + g_ascii_strncasecmp("Content-Length:", + (char *)session->line->data, 15) == 0) { + + char *end = NULL; + + session->content_len = strtol((char *) + (session->line->data + 15), &end, 10); + + debug(session->web, "content length: %d\n", + session->content_len); + } + + debug(session->web, (char *)session->line->data); + + ptr += line_len; + len -= line_len; + + /* done from curent http line header, reset for next line */ + session->line->len = 0; + } + + return 0; +} + +static int decode_function(struct web_session *session, + unsigned char *buf, int len) +{ + int err; + + /* check if we still reading HTTP header */ + if (is_set(session, WEB_FLAG_HEADER_READY) == FALSE) { + err = decode_header(session, buf, len); + + if (err <= 0) + return err; + + buf += err; + len -= err; + } + + session->total_len += len; + + if (len > 0) + if (send_client_payload(session, buf, len) == FALSE) + return -1; + + if (session->content_len != -1 && + session->total_len >= session->content_len) { + debug(session->web, "Downloan complete"); + set_flag(session, WEB_FLAG_DOWNLOAD_DONE); + } + + return 0; +} + static gboolean received_data(GIOChannel *channel, GIOCondition cond, gpointer user_data) { struct web_session *session = user_data; unsigned char buf[4096]; int sk, len; + int err; if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) { session->transport_watch = 0; @@ -216,7 +398,22 @@ static gboolean received_data(GIOChannel *channel, GIOCondition cond, session->result_func(200, session->result_data); return FALSE; } - printf("%s", buf); + + err = decode_function(session, buf, len); + + if (err < 0) { + session->transport_watch = 0; + if (session->result_func != NULL) + session->result_func(err, session->result_data); + return FALSE; + } + if (is_set(session, WEB_FLAG_DOWNLOAD_DONE) == TRUE) { + session->transport_watch = 0; + if (session->result_func != NULL) + session->result_func(session->http_status, + session->result_data); + return FALSE; + } return TRUE; } @@ -265,6 +462,8 @@ static void start_request(struct web_session *session) debug(session->web, "request %s from %s", session->request, session->host); + init_download_data(session); + sk = g_io_channel_unix_get_fd(session->transport_channel); buf = g_string_new(NULL); @@ -366,6 +565,7 @@ static void resolv_result(GResolvResultStatus status, } guint g_web_request(GWeb *web, GWebMethod method, const char *url, + GWebReceivedFunc rec_func, GWebResultFunc func, gpointer user_data) { struct web_session *session; @@ -390,9 +590,13 @@ guint g_web_request(GWeb *web, GWebMethod method, const char *url, session->result_func = func; session->result_data = user_data; + session->received_func = rec_func; + + session->line = g_byte_array_new(); session->resolv_action = g_resolv_lookup_hostname(web->resolv, - session->host, resolv_result, session); + session->host, resolv_result, session); + if (session->resolv_action == 0) { free_session(session); return 0; -- 1.7.2.3 _______________________________________________ connman mailing list connman@connman.net http://lists.connman.net/listinfo/connman