diff src/html.c @ 4331:bbd7b12986a8

[gaim-migrate @ 4595] Okay, a few new goodies in here! HTTP redirect support! Sean wants to be able to drag-and-drop themes from our new themes page, but they're hiding behind a script that redirects. Rather than lose functionality in the script, I added redirects here. Works like a charm. Smarter memory reallocation! The buffer was being reallocated every byte. That means 10,000,000 of data would cause 10,000,000 reallocations. Now it starts off with a buffer of 4096 (for HTTP headers) or 8192 (for data) and reads until it's full. When full, the buffer increases by half of the previous size. Content-Length support! The HTTP headers are scanned for a Content-Length header. If found, it uses this for the buffer instead of 8192. This should reduce the number of reallocations to 0. Have fun draggening-and-droppening. committer: Tailor Script <tailor@pidgin.im>
author Christian Hammond <chipx86@chipx86.com>
date Sat, 18 Jan 2003 00:53:42 +0000
parents a789969fc198
children 60b9f8fccce8
line wrap: on
line diff
--- a/src/html.c	Fri Jan 17 23:28:06 2003 +0000
+++ b/src/html.c	Sat Jan 18 00:53:42 2003 +0000
@@ -128,8 +128,64 @@
 	gboolean startsaving;
 	char *webdata;
 	unsigned long len;
+	unsigned long data_len;
 };
 
+static gboolean
+parse_redirect(const char *data, size_t data_len, gint sock,
+			   struct grab_url_data *gunk)
+{
+	gchar *s;
+
+	if ((s = g_strstr_len(data, data_len, "Location: ")) != NULL) {
+		gchar *new_url, *end;
+		int len;
+
+		s += strlen("Location: ");
+		end = strchr(s, '\r');
+
+		/* Just in case :) */
+		if (end == NULL)
+			end = strchr(s, '\n');
+
+		len = end - s;
+
+		new_url = g_malloc(len + 1);
+		strncpy(new_url, s, len);
+		new_url[len] = '\0';
+
+		/* Close the existing stuff. */
+		gaim_input_remove(gunk->inpa);
+		close(sock);
+
+		/* Try again, with this new location. */
+		grab_url(new_url, gunk->full, gunk->callback,
+				 gunk->data);
+
+		/* Free up. */
+		g_free(new_url);
+		g_free(gunk->webdata);
+		g_free(gunk->website);
+		g_free(gunk->url);
+		g_free(gunk);
+
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static size_t
+parse_content_len(const char *data, size_t data_len)
+{
+	gchar *s;
+	size_t content_len = 0;
+
+	sscanf(data, "Content-Length: %d", &content_len);
+
+	return content_len;
+}
+
 static void grab_url_callback(gpointer dat, gint sock, GaimInputCondition cond)
 {
 	struct grab_url_data *gunk = dat;
@@ -154,6 +210,8 @@
 		fcntl(sock, F_SETFL, O_NONBLOCK);
 		gunk->sentreq = TRUE;
 		gunk->inpa = gaim_input_add(sock, GAIM_INPUT_READ, grab_url_callback, dat);
+		gunk->data_len = 4096;
+		gunk->webdata = g_malloc(gunk->data_len);
 		return;
 	}
 
@@ -162,21 +220,51 @@
 			errno = 0;
 			return;
 		}
+
+		gunk->len++;
+
+		if (gunk->len == gunk->data_len + 1) {
+			gunk->data_len += (gunk->data_len) / 2;
+
+			gunk->webdata = g_realloc(gunk->webdata, gunk->data_len);
+		}
+
+		gunk->webdata[gunk->len - 1] = data;
+
 		if (!gunk->startsaving) {
 			if (data == '\r')
 				return;
 			if (data == '\n') {
-				if (gunk->newline)
+				if (gunk->newline) {
+					size_t content_len;
 					gunk->startsaving = TRUE;
+
+					/* See if we can find a redirect. */
+					if (parse_redirect(gunk->webdata, gunk->len, sock, gunk))
+						return;
+
+					/* No redirect. See if we can find a content length. */
+					content_len = parse_content_len(gunk->webdata, gunk->len);
+
+					if (content_len == 0) {
+						/* We'll stick with an initial 8192 */
+						content_len = 8192;
+					}
+
+					/* Out with the old... */
+					gunk->len = 0;
+					g_free(gunk->webdata);
+					gunk->webdata = NULL;
+
+					/* In with the new. */
+					gunk->data_len = content_len;
+					gunk->webdata = g_malloc(gunk->data_len);
+				}
 				else
 					gunk->newline = TRUE;
 				return;
 			}
 			gunk->newline = FALSE;
-		} else {
-			gunk->len++;
-			gunk->webdata = g_realloc(gunk->webdata, gunk->len);
-			gunk->webdata[gunk->len - 1] = data;
 		}
 	} else if (errno != ETIMEDOUT) {
 		gunk->webdata = g_realloc(gunk->webdata, gunk->len + 1);