summaryrefslogtreecommitdiff
path: root/gweb/gweb.c
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2010-11-01 00:58:50 +0100
committerMarcel Holtmann <marcel@holtmann.org>2010-11-01 00:58:50 +0100
commit278c3c7529d8440a65ff1a7c6a04b2bd27f426e9 (patch)
tree4ed18644ca25b77ed81a9ed07ce74935604e3c4f /gweb/gweb.c
parent65bbd6ca12d11c48d0333465076769abbf67476e (diff)
downloadconnman-278c3c7529d8440a65ff1a7c6a04b2bd27f426e9.tar.gz
connman-278c3c7529d8440a65ff1a7c6a04b2bd27f426e9.tar.bz2
connman-278c3c7529d8440a65ff1a7c6a04b2bd27f426e9.zip
Fix GWeb header parsing and make it more robust
Diffstat (limited to 'gweb/gweb.c')
-rw-r--r--gweb/gweb.c119
1 files changed, 52 insertions, 67 deletions
diff --git a/gweb/gweb.c b/gweb/gweb.c
index 02bc6591..177e9bd7 100644
--- a/gweb/gweb.c
+++ b/gweb/gweb.c
@@ -36,7 +36,7 @@
#include "gresolv.h"
#include "gweb.h"
-#define LINE_CHUNK_SIZE 2048
+#define DEFAULT_BUFFER_SIZE 2048
#define SESSION_FLAG_USE_TLS (1 << 0)
@@ -60,10 +60,9 @@ struct web_session {
guint resolv_action;
char *request;
- char *line_buffer;
- char *line_offset;
- unsigned int line_space;
- char *current_line;
+ guint8 *receive_buffer;
+ gsize receive_space;
+ GString *current_header;
gboolean header_done;
GWebResult result;
@@ -123,7 +122,8 @@ static void free_session(struct web_session *session)
if (session->transport_channel != NULL)
g_io_channel_unref(session->transport_channel);
- g_free(session->line_buffer);
+ g_string_free(session->current_header, TRUE);
+ g_free(session->receive_buffer);
g_free(session->host);
g_free(session->address);
@@ -309,10 +309,9 @@ static gboolean received_data(GIOChannel *channel, GIOCondition cond,
gpointer user_data)
{
struct web_session *session = user_data;
- gsize bytes_read, consumed = 0;
+ guint8 *ptr = session->receive_buffer;
+ gsize bytes_read;
GIOStatus status;
- size_t count;
- char *str;
if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
session->transport_watch = 0;
@@ -322,10 +321,11 @@ static gboolean received_data(GIOChannel *channel, GIOCondition cond,
return FALSE;
}
- status = g_io_channel_read_chars(channel, session->line_offset,
- session->line_space - 1, &bytes_read, NULL);
+ status = g_io_channel_read_chars(channel,
+ (gchar *) session->receive_buffer,
+ session->receive_space - 1, &bytes_read, NULL);
- debug(session->web, "status %u bytes read %zu", status, bytes_read);
+ debug(session->web, "bytes read %zu", bytes_read);
if (status != G_IO_STATUS_NORMAL) {
session->transport_watch = 0;
@@ -335,79 +335,60 @@ static gboolean received_data(GIOChannel *channel, GIOCondition cond,
return FALSE;
}
+ session->receive_buffer[bytes_read] = '\0';
+
if (session->header_done == TRUE) {
- session->line_buffer[bytes_read] = '\0';
+ session->result.buffer = session->receive_buffer;
session->result.length = bytes_read;
call_result_func(session, 100);
return TRUE;
}
- str = memchr(session->line_offset, '\n', bytes_read);
+ while (bytes_read > 0) {
+ guint8 *pos;
+ gsize count;
+ char *str;
- while (str != NULL) {
- char *start = session->current_line;
- unsigned int code;
+ pos = memchr(ptr, '\n', bytes_read);
+ if (pos == NULL) {
+ g_string_append_len(session->current_header,
+ (gchar *) ptr, bytes_read);
+ return TRUE;
+ }
- *str = '\0';
- count = strlen(start);
- if (count > 0 && start[count - 1] == '\r') {
- start[--count] = '\0';
- consumed++;
+ *pos = '\0';
+ count = strlen((char *) ptr);
+ if (count > 0 && ptr[count - 1] == '\r') {
+ ptr[--count] = '\0';
+ bytes_read--;
}
- session->current_line = str + 1;
- consumed += count + 1;
+ g_string_append_len(session->current_header,
+ (gchar *) ptr, count);
+
+ bytes_read -= count + 1;
+ ptr = pos + 1;
- if (count == 0) {
- const void *ptr = session->current_line;
- session->current_line[bytes_read - consumed] = '\0';
+ if (session->current_header->len == 0) {
session->header_done = TRUE;
- session->result.buffer = ptr;
- session->result.length = bytes_read - consumed;
+ session->result.buffer = pos + 1;
+ session->result.length = bytes_read;
call_result_func(session, 100);
break;
}
- //printf("[ %s ]\n", start);
+ str = session->current_header->str;
if (session->result.status == 0) {
- if (sscanf(start, "HTTP/%*s %u %*s", &code) == 1)
+ unsigned int code;
+
+ if (sscanf(str, "HTTP/%*s %u %*s", &code) == 1)
session->result.status = code;
}
- str = memchr(session->current_line, '\n',
- bytes_read - consumed);
- }
-
- if (session->header_done == TRUE) {
- gsize size = session->line_offset - session->line_buffer;
-
- session->line_offset = session->line_buffer;
- session->line_space += size;
+ debug(session->web, "[header] %s", str);
- session->result.buffer = (const guint8 *) session->line_offset;
- return TRUE;
- }
-
- session->line_offset += bytes_read;
- session->line_space -= bytes_read;
-
- if (session->line_space < 32) {
- gsize size = session->line_offset - session->line_buffer;
- gsize pos = session->current_line - session->line_buffer;
- char *buf;
-
- printf("realloc, space %u size %zu\n",
- session->line_space, size);
-
- buf = g_try_realloc(session->line_buffer,
- size + LINE_CHUNK_SIZE);
- if (buf != NULL) {
- session->line_buffer = buf;
- session->line_offset = buf + size;
- session->line_space = LINE_CHUNK_SIZE;
- session->current_line = buf + pos;
- }
+ g_string_truncate(session->current_header, 0);
}
return TRUE;
@@ -612,10 +593,14 @@ guint g_web_request(GWeb *web, GWebMethod method, const char *url,
session->result_func = func;
session->result_data = user_data;
- session->line_buffer = g_try_malloc(LINE_CHUNK_SIZE);
- session->line_offset = session->line_buffer;
- session->line_space = LINE_CHUNK_SIZE;
- session->current_line = session->line_buffer;
+ session->receive_buffer = g_try_malloc(DEFAULT_BUFFER_SIZE);
+ if (session->receive_buffer == NULL) {
+ free_session(session);
+ return 0;
+ }
+
+ session->receive_space = DEFAULT_BUFFER_SIZE;
+ session->current_header = g_string_sized_new(0);
session->header_done = FALSE;
if (inet_aton(session->host, NULL) == 0) {