--- a/libpurple/http.c Wed Oct 17 16:32:41 2012 +0200 +++ b/libpurple/http.c Wed Oct 17 17:33:11 2012 +0200 @@ -59,6 +59,7 @@ gchar *url; gchar *method; PurpleHttpHeaders *headers; + PurpleHttpCookieJar *cookie_jar; int timeout; int max_redirects; @@ -121,6 +122,13 @@ GHashTable *by_name; }; +struct _PurpleHttpCookieJar +{ + int ref_count; + + GHashTable *tab; +}; + static PurpleHttpConnection * purple_http_connection_new( PurpleHttpRequest *request, PurpleConnection *gc); static void purple_http_connection_terminate(PurpleHttpConnection *hc); @@ -128,6 +136,10 @@ static PurpleHttpResponse * purple_http_response_new(void); static void purple_http_response_free(PurpleHttpResponse *response); +static void purple_http_cookie_jar_parse(PurpleHttpCookieJar *cookie_jar, + GList *values); +gchar * purple_http_cookie_jar_dump(PurpleHttpCookieJar *cjar); + static PurpleHttpURL * purple_http_url_parse(const char *url); static void purple_http_url_free(PurpleHttpURL *parsed_url); static void purple_http_url_relative(PurpleHttpURL *base_url, @@ -160,7 +172,7 @@ 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 const GList * purple_http_headers_get_all_by_name( +static GList * purple_http_headers_get_all_by_name( PurpleHttpHeaders *hdrs, const gchar *key); static const gchar * purple_http_headers_get(PurpleHttpHeaders *hdrs, const gchar *key); @@ -254,7 +266,8 @@ return hdrs->list; } -static const GList * purple_http_headers_get_all_by_name( +/* return const */ +static GList * purple_http_headers_get_all_by_name( PurpleHttpHeaders *hdrs, const gchar *key) { GList *values; @@ -466,6 +479,8 @@ kvp->key, (gchar*)kvp->value); } + /* TODO: sending cookies */ + g_string_append_printf(h, "\r\n"); if (purple_debug_is_unsafe() && purple_debug_is_verbose()) { @@ -761,6 +776,19 @@ g_free(hdrs); } + purple_http_cookie_jar_parse(hc->request->cookie_jar, + purple_http_headers_get_all_by_name( + hc->response->headers, "Set-Cookie")); + + if (purple_debug_is_unsafe() && purple_debug_is_verbose() && + !purple_http_cookie_jar_is_empty( + hc->request->cookie_jar)) { + gchar *cookies = purple_http_cookie_jar_dump( + hc->request->cookie_jar); + purple_debug_misc("http", "Cookies: %s\n", cookies); + g_free(cookies); + } + if (hc->response->code == 407) { _purple_http_error(hc, _("Invalid proxy credentials")); return; @@ -1174,6 +1202,13 @@ return http_conn->request; } +PurpleHttpCookieJar * purple_http_conn_get_cookie_jar( + PurpleHttpConnection *http_conn) +{ + return purple_http_request_get_cookie_jar(purple_http_conn_get_request( + http_conn)); +} + PurpleConnection * purple_http_conn_get_purple_connection( PurpleHttpConnection *http_conn) { @@ -1182,6 +1217,127 @@ return http_conn->gc; } +/*** Cookie jar API ***********************************************************/ + +void purple_http_cookie_jar_free(PurpleHttpCookieJar *cookie_jar); + +PurpleHttpCookieJar * purple_http_cookie_jar_new(void) +{ + PurpleHttpCookieJar *cjar = g_new0(PurpleHttpCookieJar, 1); + + cjar->ref_count = 1; + cjar->tab = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + g_free); + + return cjar; +} + +void purple_http_cookie_jar_free(PurpleHttpCookieJar *cookie_jar) +{ + g_hash_table_destroy(cookie_jar->tab); + g_free(cookie_jar); +} + +void purple_http_cookie_jar_ref(PurpleHttpCookieJar *cookie_jar) +{ + g_return_if_fail(cookie_jar != NULL); + + cookie_jar->ref_count++; +} + +PurpleHttpCookieJar * purple_http_cookie_jar_unref( + PurpleHttpCookieJar *cookie_jar) +{ + if (cookie_jar == NULL) + return NULL; + + g_return_val_if_fail(cookie_jar->ref_count > 0, NULL); + + cookie_jar->ref_count--; + if (cookie_jar->ref_count > 0) + return cookie_jar; + + purple_http_cookie_jar_free(cookie_jar); + return NULL; +} + +static void purple_http_cookie_jar_parse(PurpleHttpCookieJar *cookie_jar, + GList *values) +{ + values = g_list_first(values); + while (values) { + const gchar *cookie = values->data; + const gchar *eqsign, *semicolon; + gchar *name, *value; + values = g_list_next(values); + + eqsign = strchr(cookie, '='); + semicolon = strchr(cookie, ';'); + + if (eqsign == NULL || eqsign == cookie || + (semicolon != NULL && semicolon < eqsign)) { + if (purple_debug_is_unsafe()) + purple_debug_warning("http", + "Invalid cookie: [%s]\n", cookie); + else + purple_debug_warning("http", "Invalid cookie."); + } + + name = g_strndup(cookie, eqsign - cookie); + eqsign++; + if (semicolon != NULL) + value = g_strndup(eqsign, semicolon - eqsign); + else + value = g_strdup(eqsign); + + /* TODO: parse removing a cookie */ + purple_http_cookie_jar_set(cookie_jar, name, value); + + g_free(name); + g_free(value); + } +} + +void purple_http_cookie_jar_set(PurpleHttpCookieJar *cookie_jar, + const gchar *name, const gchar *value) +{ + g_return_if_fail(cookie_jar != NULL); + g_return_if_fail(name != NULL); + + if (value != NULL) + g_hash_table_insert(cookie_jar->tab, g_strdup(name), g_strdup(value)); + else + g_hash_table_remove(cookie_jar->tab, name); +} + +const gchar * purple_http_cookie_jar_get(PurpleHttpCookieJar *cookie_jar, + const gchar *name) +{ + return g_hash_table_lookup(cookie_jar->tab, name); +} + +gchar * purple_http_cookie_jar_dump(PurpleHttpCookieJar *cjar) +{ + GHashTableIter it; + gchar *key, *value; + GString *str = g_string_new(""); + + g_hash_table_iter_init(&it, cjar->tab); + while (g_hash_table_iter_next(&it, (gpointer*)&key, (gpointer*)&value)) + g_string_append_printf(str, "%s: %s\n", key, value); + + if (str->len > 0) + g_string_truncate(str, str->len - 1); + return g_string_free(str, FALSE); +} + +gboolean purple_http_cookie_jar_is_empty(PurpleHttpCookieJar *cookie_jar) +{ + g_return_val_if_fail(cookie_jar != NULL, TRUE); + + return g_hash_table_size(cookie_jar->tab) == 0; +} + /*** Request API **************************************************************/ static void purple_http_request_free(PurpleHttpRequest *request); @@ -1197,6 +1353,7 @@ request->ref_count = 1; request->url = g_strdup(url); request->headers = purple_http_headers_new(); + request->cookie_jar = purple_http_cookie_jar_new(); request->timeout = PURPLE_HTTP_REQUEST_DEFAULT_TIMEOUT; request->max_redirects = PURPLE_HTTP_REQUEST_DEFAULT_MAX_REDIRECTS; @@ -1209,6 +1366,7 @@ static void purple_http_request_free(PurpleHttpRequest *request) { purple_http_headers_free(request->headers); + purple_http_cookie_jar_unref(request->cookie_jar); g_free(request->url); g_free(request); } @@ -1301,6 +1459,25 @@ return request->max_redirects; } +void purple_http_request_set_cookie_jar(PurpleHttpRequest *request, + PurpleHttpCookieJar *cookie_jar) +{ + g_return_if_fail(request != NULL); + g_return_if_fail(cookie_jar != NULL); + + purple_http_cookie_jar_ref(cookie_jar); + purple_http_cookie_jar_unref(request->cookie_jar); + request->cookie_jar = cookie_jar; +} + +PurpleHttpCookieJar * purple_http_request_get_cookie_jar( + PurpleHttpRequest *request) +{ + g_return_val_if_fail(request != NULL, NULL); + + return request->cookie_jar; +} + void purple_http_request_set_http11(PurpleHttpRequest *request, gboolean http11) { g_return_if_fail(request != NULL);