/cpw/tomkiewicz/http: 178eb69a3f11: Handle redirects
Tomasz Wasilczyk
tomkiewicz at cpw.pidgin.im
Tue Oct 16 05:43:31 EDT 2012
Changeset: 178eb69a3f113977be3e771980fcf5d00086ca0a
Author: Tomasz Wasilczyk <tomkiewicz at cpw.pidgin.im>
Date: 2012-10-16 11:43 +0200
Branch: default
URL: http://hg.pidgin.im/cpw/tomkiewicz/http/rev/178eb69a3f11
Description:
Handle redirects
diffstat:
libpurple/core.c | 3 +
libpurple/http.c | 270 ++++++++++++++++++++++++++++++++++++++-----
libpurple/http.h | 17 ++
libpurple/protocols/gg/gg.c | 35 +++++-
4 files changed, 292 insertions(+), 33 deletions(-)
diffs (truncated from 497 to 300 lines):
diff --git a/libpurple/core.c b/libpurple/core.c
--- a/libpurple/core.c
+++ b/libpurple/core.c
@@ -33,6 +33,7 @@
#include "debug.h"
#include "dnsquery.h"
#include "ft.h"
+#include "http.h"
#include "idle.h"
#include "imgstore.h"
#include "network.h"
@@ -174,6 +175,7 @@ purple_core_init(const char *ui)
purple_stun_init();
purple_xfers_init();
purple_idle_init();
+ purple_http_init();
purple_smileys_init();
/*
* Call this early on to try to auto-detect our IP address and
@@ -222,6 +224,7 @@ purple_core_quit(void)
/* Save .xml files, remove signals, etc. */
purple_smileys_uninit();
+ purple_http_uninit();
purple_idle_uninit();
purple_pounces_uninit();
purple_blist_uninit();
diff --git a/libpurple/http.c b/libpurple/http.c
--- a/libpurple/http.c
+++ b/libpurple/http.c
@@ -29,6 +29,8 @@
#include "internal.h"
#include "debug.h"
+#define PURPLE_HTTP_URL_CREDENTIALS_CHARS "a-z0-9.,~_/*!&%?=+\\^-"
+
typedef struct _PurpleHttpURL PurpleHttpURL;
typedef struct _PurpleHttpSocket PurpleHttpSocket;
@@ -85,11 +87,12 @@ struct _PurpleHttpResponse
struct _PurpleHttpURL
{
gchar *protocol;
+ gchar *user;
+ gchar *password;
gchar *host;
int port;
gchar *path;
- gchar *user;
- gchar *password;
+ gchar *fragment;
};
struct _PurpleHttpHeaders
@@ -107,8 +110,11 @@ 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 void purple_http_url_relative(PurpleHttpURL *base_url,
+ PurpleHttpURL *relative_url);
+static gchar * purple_http_url_print(PurpleHttpURL *parsed_url);
-static gchar * purple_http_url_print(PurpleHttpURL *parsed_url);
+static GRegex *purple_http_re_url, *purple_http_re_url_host;
/*** Headers collection *******************************************************/
@@ -510,6 +516,7 @@ static void _purple_http_recv(gpointer _
return;
}
+ /* EOF */
if (len == 0) {
if (hc->length_expected >= 0 &&
hc->length_got < hc->length_expected) {
@@ -558,6 +565,8 @@ static void _purple_http_recv(gpointer _
hc->length_expected = hc->length_got;
if (hc->length_expected >= 0 && hc->length_got >= hc->length_expected) {
+ const gchar *redirect;
+
if (!hc->headers_got) {
hc->response->code = 0;
purple_debug_warning("http", "No headers got\n");
@@ -573,6 +582,29 @@ static void _purple_http_recv(gpointer _
g_free(hdrs);
}
+ redirect = purple_http_headers_get(hc->response->headers,
+ "location");
+ if (redirect) {
+ PurpleHttpURL *url = purple_http_url_parse(redirect);
+
+ if (!url) {
+ if (purple_debug_is_unsafe())
+ purple_debug_warning("http",
+ "Invalid redirect to %s\n",
+ redirect);
+ else
+ purple_debug_warning("http",
+ "Invalid redirect\n");
+ _purple_http_error(hc, _("Error parsing HTTP"));
+ }
+
+ purple_http_url_relative(hc->url, url);
+ purple_http_url_free(url);
+
+ _purple_http_reconnect(hc);
+ return;
+ }
+
_purple_http_disconnect(hc);
purple_http_connection_terminate(hc);
return;
@@ -750,6 +782,8 @@ static gboolean _purple_http_reconnect(P
url->host, url->port,
_purple_http_connected_ssl,
_purple_http_connected_ssl_error, hc);
+// purple_ssl_set_compatibility_level(hc->socket.ssl_connection,
+// PURPLE_SSL_COMPATIBILITY_SECURE);
} else {
hc->socket.raw_connection = purple_proxy_connect(hc->gc, account,
url->host, url->port,
@@ -1003,38 +1037,116 @@ const gchar * purple_http_response_get_d
/*** URL functions ************************************************************/
-static PurpleHttpURL * purple_http_url_parse(const char *url)
+static PurpleHttpURL * purple_http_url_parse(const char *raw_url)
{
- PurpleHttpURL *parsed_url;
+ PurpleHttpURL *url;
+ GMatchInfo *match_info;
- g_return_val_if_fail(url != NULL, NULL);
+ gchar *host_full, *tmp;
- parsed_url = g_new0(PurpleHttpURL, 1);
+ g_return_val_if_fail(raw_url != NULL, NULL);
- if (!purple_url_parse(url,
- &parsed_url->protocol,
- &parsed_url->host,
- &parsed_url->port,
- &parsed_url->path,
- &parsed_url->user,
- &parsed_url->password)) {
- g_free(parsed_url);
+ url = g_new0(PurpleHttpURL, 1);
+
+ if (!g_regex_match(purple_http_re_url, raw_url, 0, &match_info)) {
+ if (purple_debug_is_verbose() && purple_debug_is_unsafe()) {
+ purple_debug_warning("http",
+ "Invalid URL provided: %s\n",
+ raw_url);
+ }
return NULL;
}
- if (parsed_url->host[0] != '\0' &&
- parsed_url->path[0] != '\0') {
- gchar *tmp = parsed_url->path;
- parsed_url->path = g_strdup_printf("/%s", parsed_url->path);
+ url->protocol = g_match_info_fetch(match_info, 1);
+ host_full = g_match_info_fetch(match_info, 2);
+ url->path = g_match_info_fetch(match_info, 3);
+ url->fragment = g_match_info_fetch(match_info, 4);
+ g_match_info_free(match_info);
+
+ if (url->protocol[0] == '\0') {
+ g_free(url->protocol);
+ url->protocol = NULL;
+ } else if (url->protocol != NULL) {
+ tmp = url->protocol;
+ url->protocol = g_ascii_strdown(url->protocol, -1);
g_free(tmp);
}
+ if (host_full[0] == '\0') {
+ g_free(host_full);
+ host_full = NULL;
+ }
+ if (url->path[0] == '\0') {
+ g_free(url->path);
+ url->path = NULL;
+ }
+ if ((url->protocol == NULL) != (host_full == NULL))
+ purple_debug_warning("http", "Protocol or host not present "
+ "(unlikely case)\n");
- if (parsed_url->path[0] == '\0') {
- g_free(parsed_url->path);
- parsed_url->path = g_strdup("/");
+ if (host_full) {
+ gchar *port_str;
+
+ if (!g_regex_match(purple_http_re_url_host, host_full, 0,
+ &match_info)) {
+ if (purple_debug_is_verbose() &&
+ purple_debug_is_unsafe()) {
+ purple_debug_warning("http",
+ "Invalid host provided for URL: %s\n",
+ raw_url);
+ }
+
+ g_free(host_full);
+ purple_http_url_free(url);
+ return NULL;
+ }
+
+ url->user = g_match_info_fetch(match_info, 1);
+ url->password = g_match_info_fetch(match_info, 2);
+ url->host = g_match_info_fetch(match_info, 3);
+ port_str = g_match_info_fetch(match_info, 4);
+
+ if (port_str && port_str[0])
+ url->port = atoi(port_str);
+
+ if (url->user[0] == '\0') {
+ g_free(url->user);
+ url->user = NULL;
+ }
+ if (url->password[0] == '\0') {
+ g_free(url->password);
+ url->password = NULL;
+ }
+ if (url->host[0] == '\0') {
+ g_free(url->host);
+ url->host = NULL;
+ } else if (url->host != NULL) {
+ tmp = url->host;
+ url->host = g_ascii_strdown(url->host, -1);
+ g_free(tmp);
+ }
+
+ g_free(port_str);
+ g_match_info_free(match_info);
+
+ g_free(host_full);
+ host_full = NULL;
}
- return parsed_url;
+ if (url->host != NULL) {
+ if (url->protocol == NULL)
+ url->protocol = g_strdup("http");
+ if (url->port == 0 && 0 == strcmp(url->protocol, "http"))
+ url->port = 80;
+ if (url->port == 0 && 0 == strcmp(url->protocol, "https"))
+ url->port = 443;
+ if (url->path == NULL)
+ url->path = g_strdup("/");
+ if (url->path[0] != '/')
+ purple_debug_warning("http",
+ "URL path doesn't start with slash\n");
+ }
+
+ return url;
}
static void purple_http_url_free(PurpleHttpURL *parsed_url)
@@ -1043,46 +1155,140 @@ static void purple_http_url_free(PurpleH
return;
g_free(parsed_url->protocol);
+ g_free(parsed_url->user);
+ g_free(parsed_url->password);
g_free(parsed_url->host);
g_free(parsed_url->path);
- g_free(parsed_url->user);
- g_free(parsed_url->password);
+ g_free(parsed_url->fragment);
g_free(parsed_url);
}
+static void purple_http_url_relative(PurpleHttpURL *base_url,
+ PurpleHttpURL *relative_url)
+{
+ g_return_if_fail(base_url != NULL);
+ g_return_if_fail(relative_url != NULL);
+
+ if (relative_url->host) {
+ g_free(base_url->protocol);
+ base_url->protocol = g_strdup(relative_url->protocol);
+ g_free(base_url->user);
+ base_url->user = g_strdup(relative_url->user);
+ g_free(base_url->password);
+ base_url->password = g_strdup(relative_url->password);
+ g_free(base_url->host);
+ base_url->host = g_strdup(relative_url->host);
+ base_url->port = relative_url->port;
+
+ g_free(base_url->path);
+ base_url->path = NULL;
+ }
+
+ if (relative_url->path) {
+ if (relative_url->path[0] == '/' ||
+ base_url->path == NULL) {
+ g_free(base_url->path);
+ base_url->path = g_strdup(relative_url->path);
More information about the Commits
mailing list