From 11e5f0cbf33f9ef3d5af7a7989cae51b0e963884 Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Mon, 27 Dec 2010 14:17:40 -0800 Subject: [PATCH] Add g_web_result_get_header support. Add all http response header to hash table and allow user to get these header values. Header with same key will be replaced by last header value. --- gweb/gweb.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------- gweb/gweb.h | 2 ++ 2 files changed, 88 insertions(+), 13 deletions(-) diff --git a/gweb/gweb.c b/gweb/gweb.c index a348cdd..c6a76cc 100644 --- a/gweb/gweb.c +++ b/gweb/gweb.c @@ -52,6 +52,8 @@ struct _GWebResult { const guint8 *buffer; gsize length; gboolean use_chunk; + gchar *last_key; + GHashTable *headers; }; struct web_session { @@ -148,6 +150,9 @@ static void free_session(struct web_session *session) if (session->transport_channel != NULL) g_io_channel_unref(session->transport_channel); + g_free(session->result.last_key); + g_hash_table_destroy(session->result.headers); + g_string_free(session->send_buffer, TRUE); g_string_free(session->current_header, TRUE); g_free(session->receive_buffer); @@ -718,7 +723,23 @@ static gboolean received_data(GIOChannel *channel, GIOCondition cond, ptr = NULL; if (session->current_header->len == 0) { + char *val; + session->header_done = TRUE; + + val = g_hash_table_lookup(session->result.headers, + "Transfer-Encoding"); + if (val != NULL) { + val = g_strrstr(val, "chunked"); + if (val != NULL) { + session->result.use_chunk = TRUE; + + session->chunck_state = CHUNK_SIZE; + session->chunk_left = 0; + session->total_len = 0; + } + } + if (handle_body(session, ptr, bytes_read) < 0) { session->transport_watch = 0; return FALSE; @@ -733,23 +754,51 @@ static gboolean received_data(GIOChannel *channel, GIOCondition cond, if (sscanf(str, "HTTP/%*s %u %*s", &code) == 1) session->result.status = code; - } else if (session->result.use_chunk == FALSE && - g_ascii_strncasecmp("Transfer-Encoding:", - str, 18) == 0) { - char *val; + } - val = g_strrstr(str + 18, "chunked"); - if (val != NULL) { - session->result.use_chunk = TRUE; + debug(session->web, "[header] %s", str); - session->chunck_state = CHUNK_SIZE; - session->chunk_left = 0; - session->chunk_left = 0; - session->total_len = 0; + /* handle multi-line header */ + if (str[0] == ' ' || str[0] == '\t') { + gchar *value; + + while (str[0] == ' ' || str[0] == '\t') + str++; + + count = str - session->current_header->str; + if (count > 0) { + g_string_erase(session->current_header, + 0, count); + g_string_insert_c(session->current_header, + 0, ' '); } - } - debug(session->web, "[header] %s", str); + value = g_hash_table_lookup(session->result.headers, + session->result.last_key); + if (value != NULL) { + g_string_insert(session->current_header, + 0, value); + + str = session->current_header->str; + + g_hash_table_replace(session->result.headers, + g_strdup(session->result.last_key), + g_strdup(str)); + } + } else { + pos = memchr(str, ':', session->current_header->len); + if (pos != NULL) { + *pos = '\0'; + pos++; + + g_hash_table_replace(session->result.headers, + g_strdup(str), + g_strdup((char *)pos)); + + g_free(session->result.last_key); + session->result.last_key = g_strdup(str); + } + } g_string_truncate(session->current_header, 0); } @@ -943,6 +992,13 @@ static guint do_request(GWeb *web, const char *url, return 0; } + session->result.headers = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); + if (session->result.headers == NULL) { + free_session(session); + return 0; + } + session->receive_space = DEFAULT_BUFFER_SIZE; session->send_buffer = g_string_sized_new(0); session->current_header = g_string_sized_new(0); @@ -1016,6 +1072,23 @@ gboolean g_web_result_get_chunk(GWebResult *result, return TRUE; } +gboolean g_web_result_get_header(GWebResult *result, + const char *header, const char **value) +{ + if (result == NULL) + return FALSE; + + if (value == NULL) + return FALSE; + + *value = g_hash_table_lookup(result->headers, header); + + if (*value == NULL) + return FALSE; + + return TRUE; +} + struct _GWebParser { gint ref_count; char *begin_token; diff --git a/gweb/gweb.h b/gweb/gweb.h index 5bbcc9a..2979db5 100644 --- a/gweb/gweb.h +++ b/gweb/gweb.h @@ -75,6 +75,8 @@ gboolean g_web_cancel_request(GWeb *web, guint id); guint16 g_web_result_get_status(GWebResult *result); +gboolean g_web_result_get_header(GWebResult *result, + const char *header, const char **value); gboolean g_web_result_get_chunk(GWebResult *result, const guint8 **chunk, gsize *length); -- 2.7.4