/cpw/tomkiewicz/http: 9c4acb75b2e6: Let's parse response headers
Tomasz Wasilczyk
tomkiewicz at cpw.pidgin.im
Sat Oct 13 07:57:05 EDT 2012
Changeset: 9c4acb75b2e6f0feb3fc316bb7808eed5355d79f
Author: Tomasz Wasilczyk <tomkiewicz at cpw.pidgin.im>
Date: 2012-10-13 13:56 +0200
Branch: default
URL: http://hg.pidgin.im/cpw/tomkiewicz/http/rev/9c4acb75b2e6
Description:
Let's parse response headers
diffstat:
libpurple/http.c | 216 ++++++++++++++++++++++++++++++++++++++++++++++++------
libpurple/http.h | 4 +-
2 files changed, 194 insertions(+), 26 deletions(-)
diffs (truncated from 349 to 300 lines):
diff --git a/libpurple/http.c b/libpurple/http.c
--- a/libpurple/http.c
+++ b/libpurple/http.c
@@ -33,9 +33,10 @@ typedef struct _PurpleHttpURL PurpleHttp
typedef struct _PurpleHttpSocket PurpleHttpSocket;
+typedef struct _PurpleHttpHeaders PurpleHttpHeaders;
+
struct _PurpleHttpSocket
{
- gboolean is_connected;
gboolean is_ssl;
PurpleSslConnection *ssl_connection;
PurpleProxyConnectData *raw_connection;
@@ -63,6 +64,8 @@ struct _PurpleHttpConnection
PurpleHttpSocket socket;
GString *request_header;
int request_header_written;
+ gboolean main_header_got, headers_got;
+ GString *response_buffer;
};
struct _PurpleHttpResponse
@@ -72,6 +75,7 @@ struct _PurpleHttpResponse
gchar *data;
gsize data_len;
+ PurpleHttpHeaders *headers;
};
struct _PurpleHttpURL
@@ -84,6 +88,12 @@ struct _PurpleHttpURL
gchar *password;
};
+struct _PurpleHttpHeaders
+{
+ GList *list;
+ GHashTable *by_name;
+};
+
static PurpleHttpConnection * purple_http_connection_new(
PurpleHttpRequest *request);
static void purple_http_connection_terminate(PurpleHttpConnection *hc);
@@ -94,21 +104,90 @@ static void purple_http_response_free(Pu
static PurpleHttpURL * purple_http_url_parse(const char *url);
static void purple_http_url_free(PurpleHttpURL *parsed_url);
-static const gchar * purple_http_url_debug(PurpleHttpURL *parsed_url);
+//static const gchar * purple_http_url_debug(PurpleHttpURL *parsed_url);
+
+/*** Headers collection *******************************************************/
+
+static PurpleHttpHeaders * purple_http_headers_new(void);
+static void purple_http_headers_free(PurpleHttpHeaders *hdrs);
+static void purple_http_headers_add(PurpleHttpHeaders *hdrs, const gchar *key,
+ const gchar *value);
+static const GList * purple_http_headers_get_all(PurpleHttpHeaders *hdrs);
+static gchar * purple_http_headers_dump(PurpleHttpHeaders *hdrs);
+
+static PurpleHttpHeaders * purple_http_headers_new(void)
+{
+ PurpleHttpHeaders *hdrs = g_new0(PurpleHttpHeaders, 1);
+
+ hdrs->by_name = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify)g_list_free);
+
+ return hdrs;
+}
+
+static void purple_http_headers_free_kvp(PurpleKeyValuePair *kvp)
+{
+ g_free(kvp->key);
+ g_free(kvp->value);
+ g_free(kvp);
+}
+
+static void purple_http_headers_free(PurpleHttpHeaders *hdrs)
+{
+ if (hdrs == NULL)
+ return;
+
+ g_hash_table_destroy(hdrs->by_name);
+ g_list_free_full(hdrs->list,
+ (GDestroyNotify)purple_http_headers_free_kvp);
+ g_free(hdrs);
+}
+
+static void purple_http_headers_add(PurpleHttpHeaders *hdrs, const gchar *key,
+ const gchar *value)
+{
+ PurpleKeyValuePair *kvp;
+ GList *named_values;
+
+ g_return_if_fail(hdrs != NULL);
+ g_return_if_fail(key != NULL);
+ g_return_if_fail(value != NULL);
+
+ kvp = g_new0(PurpleKeyValuePair, 1);
+ kvp->key = g_strdup(key);
+ kvp->value = g_strdup(value);
+ hdrs->list = g_list_append(hdrs->list, kvp);
+
+ named_values = g_hash_table_lookup(hdrs->by_name, value);
+ named_values = g_list_append(named_values, kvp->value);
+ g_hash_table_replace(hdrs->by_name, g_strdup(key), named_values);
+}
+
+static const GList * purple_http_headers_get_all(PurpleHttpHeaders *hdrs)
+{
+ return hdrs->list;
+}
+
+static gchar * purple_http_headers_dump(PurpleHttpHeaders *hdrs)
+{
+ const GList *hdr;
+
+ GString *s = g_string_new("");
+
+ hdr = purple_http_headers_get_all(hdrs);
+ while (hdr) {
+ PurpleKeyValuePair *kvp = hdr->data;
+ hdr = g_list_next(hdr);
+
+ g_string_append_printf(s, "%s: %s%s", kvp->key,
+ (gchar*)kvp->value, hdr ? "\n" : "");
+ }
+
+ return g_string_free(s, FALSE);
+}
/*** HTTP protocol backend ****************************************************/
-static void purple_http_dummy_success(PurpleHttpConnection *hc)
-{
- PurpleHttpResponse *response = hc->response;
-
- response->code = 200;
- response->data = g_strdup(purple_http_url_debug(hc->url));
- response->data_len = strlen(response->data);
-
- purple_http_conn_cancel(hc);
-}
-
static void _purple_http_disconnect(PurpleHttpConnection *hc);
static void _purple_http_gen_headers(PurpleHttpConnection *hc);
@@ -185,12 +264,57 @@ static void _purple_http_gen_headers(Pur
}
}
+static void _purple_http_recv_headers(PurpleHttpConnection *hc,
+ const gchar *buf, int len)
+{
+ gchar *eol, *delim;
+
+ g_string_append_len(hc->response_buffer, buf, len); //TODO: check max buffer length, not to raise to infinity
+ while ((eol = strstr(hc->response_buffer->str, "\r\n"))
+ != NULL) {
+ gchar *hdrline = hc->response_buffer->str;
+ int hdrline_len = eol - hdrline;
+
+ hdrline[hdrline_len] = '\0';
+
+ if (hdrline[0] == '\0') {
+ if (!hc->main_header_got) {
+ hc->response->code = 0;
+ _purple_http_error(hc, _("Error parsing HTTP"));
+ return;
+ }
+ hc->headers_got = TRUE;
+ } else if (!hc->main_header_got) {
+ hc->main_header_got = TRUE;
+ delim = strchr(hdrline, ' ');
+ if (delim == NULL || 1 != sscanf(delim + 1, "%d",
+ &hc->response->code)) {
+ _purple_http_error(hc, _("Error parsing HTTP"));
+ return;
+ }
+ } else {
+ delim = strchr(hdrline, ':');
+ if (delim == NULL || delim == hdrline) {
+ _purple_http_error(hc, _("Error parsing HTTP"));
+ return;
+ }
+ *delim++ = '\0';
+ while (*delim == ' ')
+ delim++;
+
+ purple_http_headers_add(hc->response->headers, hdrline, delim);
+ }
+
+ g_string_erase(hc->response_buffer, 0, hdrline_len + 2);
+ }
+}
+
static void _purple_http_recv(gpointer _hc, gint fd, PurpleInputCondition cond)
{
PurpleHttpConnection *hc = _hc;
PurpleHttpSocket *hs = &hc->socket;
int len;
- char buf[4096];
+ gchar buf[4096];
purple_debug_misc("http", "[tmp] reading...\n");
@@ -209,7 +333,29 @@ static void _purple_http_recv(gpointer _
}
if (len == 0) { /* TODO: eof only? */
- purple_http_dummy_success(hc);
+ if (!hc->headers_got) {
+ hc->response->code = 0;
+ _purple_http_error(hc, _("Error parsing HTTP"));
+ return;
+ }
+
+ if (purple_debug_is_unsafe() && purple_debug_is_verbose()) {
+ gchar *hdrs = purple_http_headers_dump(
+ hc->response->headers);
+ purple_debug_misc("http", "Got response headers: %s\n",
+ hdrs);
+ g_free(hdrs);
+ }
+
+ _purple_http_disconnect(hc);
+ purple_http_connection_terminate(hc);
+ return;
+ }
+
+ if (!hc->headers_got) {
+ _purple_http_recv_headers(hc, buf, len);
+ /* TODO: flush hc->response_buffer to body */
+ return;
}
}
@@ -313,14 +459,14 @@ static void _purple_http_disconnect(Purp
g_return_if_fail(hc != NULL);
+ hs = &hc->socket;
+
if (hc->request_header)
g_string_free(hc->request_header, TRUE);
hc->request_header = NULL;
-
- hs = &hc->socket;
-
- if (!hs->is_connected)
- return;
+ if (hc->response_buffer)
+ g_string_free(hc->response_buffer, TRUE);
+ hc->response_buffer = NULL;
if (hs->inpa != 0)
purple_input_remove(hs->inpa);
@@ -387,7 +533,12 @@ static gboolean _purple_http_reconnect(P
_purple_http_error(hc, _("Unable to connect to %s"), url->host);
return FALSE;
}
- hc->socket.is_connected = TRUE;
+
+ purple_http_headers_free(hc->response->headers);
+ hc->response->headers = purple_http_headers_new();
+ hc->response_buffer = g_string_new("");
+ hc->main_header_got = FALSE;
+ hc->headers_got = FALSE;
return TRUE;
}
@@ -466,9 +617,6 @@ static void purple_http_connection_free(
if (hc->request_header)
g_string_free(hc->request_header, TRUE);
- if (hc->socket.is_connected)
- purple_debug_error("http", "Socket is still connected!");
-
g_free(hc);
}
@@ -556,15 +704,30 @@ static PurpleHttpResponse * purple_http_
static void purple_http_response_free(PurpleHttpResponse *response)
{
+ g_free(response->data);
g_free(response->error);
+ purple_http_headers_free(response->headers);
g_free(response);
}
gboolean purple_http_response_is_successfull(PurpleHttpResponse *response)
{
+ int code;
+
g_return_val_if_fail(response != NULL, FALSE);
- return response->code == 200; /* just temporary */
+ code = response->code;
More information about the Commits
mailing list