diff -Npur pidgin-2.6.6.old/libpurple/util.c pidgin-2.6.6/libpurple/util.c
--- pidgin-2.6.6.old/libpurple/util.c	2014-03-14 12:17:31.660859864 +0800
+++ pidgin-2.6.6/libpurple/util.c	2014-03-14 12:17:49.322899074 +0800
@@ -28,10 +28,15 @@
 #include "core.h"
 #include "debug.h"
 #include "notify.h"
+#include "ntlm.h"
 #include "prpl.h"
 #include "prefs.h"
 #include "util.h"
 
+/* 512KiB Default value for maximum HTTP download size (when the client hasn't
+   specified a length) */
+#define DEFAULT_MAX_HTTP_DOWNLOAD (512 * 1024)
+
 struct _PurpleUtilFetchUrlData
 {
 	PurpleUtilFetchUrlCallback callback;
@@ -67,8 +72,9 @@ struct _PurpleUtilFetchUrlData
 	char *webdata;
 	gsize len;
 	unsigned long data_len;
-	gssize max_len;
+	gsize max_len;
 	gboolean chunked;
+	PurpleAccount *account;
 };
 
 static char *custom_user_dir = NULL;
@@ -3373,24 +3243,26 @@ purple_strcasereplace(const char *string
 	return ret;
 }
 
-const char *
-purple_strcasestr(const char *haystack, const char *needle)
+/** TODO: Expose this when we can add API */
+static const char *
+purple_strcasestr_len(const char *haystack, gssize hlen, const char *needle, gssize nlen)
 {
-	size_t hlen, nlen;
 	const char *tmp, *ret;
 
 	g_return_val_if_fail(haystack != NULL, NULL);
 	g_return_val_if_fail(needle != NULL, NULL);
 
-	hlen = strlen(haystack);
-	nlen = strlen(needle);
+	if (hlen == -1)
+		hlen = strlen(haystack);
+	if (nlen == -1)
+		nlen = strlen(needle);
 	tmp = haystack,
 	ret = NULL;
 
 	g_return_val_if_fail(hlen > 0, NULL);
 	g_return_val_if_fail(nlen > 0, NULL);
 
-	while (*tmp && !ret) {
+	while (*tmp && !ret && (hlen - (tmp - haystack)) >= nlen) {
 		if (!g_ascii_strncasecmp(needle, tmp, nlen))
 			ret = tmp;
 		else
@@ -3400,6 +3272,12 @@ purple_strcasestr(const char *haystack,
 	return ret;
 }
 
+const char *
+purple_strcasestr(const char *haystack, const char *needle)
+{
+	return purple_strcasestr_len(haystack, -1, needle, -1);
+}
+
 char *
 purple_str_size_to_units(size_t size)
 {
@@ -3707,7 +3588,7 @@ static void ssl_url_fetch_connect_cb(gpo
 static void ssl_url_fetch_error_cb(PurpleSslConnection *ssl_connection, PurpleSslErrorType error, gpointer data);
 
 static gboolean
-parse_redirect(const char *data, size_t data_len,
+parse_redirect(const char *data, gsize data_len,
 			   PurpleUtilFetchUrlData *gfud)
 {
 	gchar *s;
@@ -3812,20 +3693,21 @@ parse_redirect(const char *data, size_t
 	return TRUE;
 }
 
+/* find the starting point of the content for the specified header and make
+ * sure that the content is safe to pass to sscanf */
 static const char *
-find_header_content(const char *data, size_t data_len, const char *header, size_t header_len)
+find_header_content(const char *data, gsize data_len, const char *header)
 {
 	const char *p = NULL;
 
-	if (header_len <= 0)
-		header_len = strlen(header);
+	gsize header_len = strlen(header);
 
-	/* Note: data is _not_ nul-terminated.  */
 	if (data_len > header_len) {
+		/* Check if the first header matches (data won't start with a \n") */
 		if (header[0] == '\n')
 			p = (g_ascii_strncasecmp(data, header + 1, header_len - 1) == 0) ? data : NULL;
 		if (!p)
-			p = purple_strcasestr(data, header);
+			p = purple_strcasestr_len(data, data_len, header, header_len);
 		if (p)
 			p += header_len;
 	}
@@ -3841,13 +3723,13 @@ find_header_content(const char *data, si
 	return NULL;
 }
 
-static size_t
-parse_content_len(const char *data, size_t data_len)
+static gsize 
+parse_content_len(const char *data, gsize data_len)
 {
-	size_t content_len = 0;
+	gsize content_len = 0;
 	const char *p = NULL;
 
-	p = find_header_content(data, data_len, "\nContent-Length: ", sizeof("\nContent-Length: ") - 1);
+	p = find_header_content(data, data_len, "\nContent-Length: ");
 	if (p) {
 		sscanf(p, "%" G_GSIZE_FORMAT, &content_len);
 		purple_debug_misc("util", "parsed %" G_GSIZE_FORMAT "\n", content_len);
@@ -3857,9 +3739,9 @@ parse_content_len(const char *data, size
 }
 
 static gboolean
-content_is_chunked(const char *data, size_t data_len)
+content_is_chunked(const char *data, gsize data_len)
 {
-	const char *p = find_header_content(data, data_len, "\nTransfer-Encoding: ", sizeof("\nTransfer-Encoding: ") - 1);
+	const char *p = find_header_content(data, data_len, "\nTransfer-Encoding: ");
 	if (p && g_ascii_strncasecmp(p, "chunked", 7) == 0)
 		return TRUE;
 
@@ -3942,7 +3824,7 @@ url_fetch_recv_cb(gpointer url_data, gin
 	while ((gfud->is_ssl && ((len = purple_ssl_read(gfud->ssl_connection, buf, sizeof(buf))) > 0)) ||
 			(!gfud->is_ssl && (len = read(source, buf, sizeof(buf))) > 0))
 	{
-		if(gfud->max_len != -1 && (gfud->len + len) > gfud->max_len) {
+		if((gfud->len + len) > gfud->max_len) {
 			purple_util_fetch_url_error(gfud, _("Error reading from %s: response too long (%d bytes limit)"),
 						    gfud->website.address, gfud->max_len);
 			return;
@@ -3965,13 +3847,13 @@ url_fetch_recv_cb(gpointer url_data, gin
 		gfud->webdata[gfud->len] = '\0';
 
 		if(!gfud->got_headers) {
-			char *tmp;
+			char *end_of_headers;
 
 			/* See if we've reached the end of the headers yet */
-			if((tmp = strstr(gfud->webdata, "\r\n\r\n"))) {
-				char * new_data;
-				guint header_len = (tmp + 4 - gfud->webdata);
-				size_t content_len;
+			end_of_headers = strstr(gfud->webdata, "\r\n\r\n");
+			if (end_of_headers) {
+				guint header_len = (end_of_headers + 4 - gfud->webdata);
+				gsize content_len;
 
 				purple_debug_misc("util", "Response headers: '%.*s'\n",
 					header_len, gfud->webdata);
@@ -3986,28 +3868,46 @@ url_fetch_recv_cb(gpointer url_data, gin
 				content_len = parse_content_len(gfud->webdata, header_len);
 				gfud->chunked = content_is_chunked(gfud->webdata, header_len);
 
-				if(content_len == 0) {
+				if (content_len == 0) {
 					/* We'll stick with an initial 8192 */
 					content_len = 8192;
 				} else {
 					gfud->has_explicit_data_len = TRUE;
+					if (content_len > gfud->max_len) {
+						purple_debug_error("util",
+								"Overriding explicit Content-Length of %" G_GSIZE_FORMAT " with max of %" G_GSSIZE_FORMAT "\n",
+								content_len, gfud->max_len);
+						content_len = gfud->max_len;
+					}
 				}
 
 
 				/* If we're returning the headers too, we don't need to clean them out */
-				if(gfud->include_headers) {
+				if (gfud->include_headers) {
+					char *new_data;
 					gfud->data_len = content_len + header_len;
-					gfud->webdata = g_realloc(gfud->webdata, gfud->data_len);
-				} else {
-					size_t body_len = 0;
+					new_data = g_try_realloc(gfud->webdata, gfud->data_len);
+					if (new_data == NULL) {
+						purple_debug_error("util",
+								"Failed to allocate %" G_GSIZE_FORMAT " bytes: %s\n",
+								content_len, g_strerror(errno));
+						purple_util_fetch_url_error(gfud,
+								_("Unable to allocate enough memory to hold "
+								  "the contents from %s.  The web server may "
+								  "be trying something malicious."),
+								gfud->website.address);
 
-					if(gfud->len > (header_len + 1))
-						body_len = (gfud->len - header_len);
+						return;
+					}
+					gfud->webdata = new_data;
+				} else {
+					char *new_data;
+					gsize body_len = gfud->len - header_len;
 
 					content_len = MAX(content_len, body_len);
 
 					new_data = g_try_malloc(content_len);
-					if(new_data == NULL) {
+					if (new_data == NULL) {
 						purple_debug_error("util",
 								"Failed to allocate %" G_GSIZE_FORMAT " bytes: %s\n",
 								content_len, g_strerror(errno));
@@ -4021,9 +3921,8 @@ url_fetch_recv_cb(gpointer url_data, gin
 					}
 
 					/* We may have read part of the body when reading the headers, don't lose it */
-					if(body_len > 0) {
-						tmp += 4;
-						memcpy(new_data, tmp, body_len);
+					if (body_len > 0) {
+						memcpy(new_data, end_of_headers + 4, body_len);
 					}
 
 					/* Out with the old... */
@@ -4257,7 +4188,12 @@ purple_util_fetch_url_request_len_with_a
 	gfud->request = g_strdup(request);
 	gfud->include_headers = include_headers;
 	gfud->fd = -1;
-	gfud->max_len = max_len;
+	if (max_len <= 0) {
+		max_len = DEFAULT_MAX_HTTP_DOWNLOAD;
+		purple_debug_error("util", "Defaulting max download from %s to %" G_GSSIZE_FORMAT "\n", url, max_len);
+	}
+	gfud->max_len = (gsize) max_len;
+	gfud->account = account;
 
 	purple_url_parse(url, &gfud->website.address, &gfud->website.port,
 				   &gfud->website.page, &gfud->website.user, &gfud->website.passwd);
