From: Mohamed Abbas <[email protected]>
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
[email protected]
http://lists.connman.net/listinfo/connman