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

Reply via email to