diff src/util.c @ 13200:33bef17125c2

[gaim-migrate @ 15563] This is the soon-to-be-infamous nonblocking network activity patch that I've been working on. Feel free to yell at me if this makes you unhappy. committer: Tailor Script <tailor@pidgin.im>
author Daniel Atallah <daniel.atallah@gmail.com>
date Thu, 09 Feb 2006 04:17:56 +0000
parents b230ed49c5d1
children 15b3926e2147
line wrap: on
line diff
--- a/src/util.c	Thu Feb 09 04:14:54 2006 +0000
+++ b/src/util.c	Thu Feb 09 04:17:56 2006 +0000
@@ -49,12 +49,12 @@
 	char *user_agent;
 	gboolean http11;
 	char *request;
+	gsize request_written;
 	gboolean include_headers;
 
 	int inpa;
 
-	gboolean sentreq;
-	gboolean startsaving;
+	gboolean got_headers;
 	gboolean has_explicit_data_len;
 	char *webdata;
 	unsigned long len;
@@ -3218,6 +3218,7 @@
 	return content_len;
 }
 
+
 static void
 url_fetched_cb(gpointer url_data, gint sock, GaimInputCondition cond)
 {
@@ -3227,70 +3228,11 @@
 	char *data_cursor;
 	gboolean got_eof = FALSE;
 
-	if (sock == -1)
-	{
-		gfud->callback(gfud->user_data, NULL, 0);
-
-		destroy_fetch_url_data(gfud);
-
-		return;
-	}
-
-	if (!gfud->sentreq)
-	{
-		char *send;
-		char buf[1024];
-
-		if (gfud->request) {
-			send = gfud->request;
-		} else {
-			if (gfud->user_agent) {
-				/* Host header is not forbidden in HTTP/1.0 requests, and HTTP/1.1
-				 * clients must know how to handle the "chunked" transfer encoding.
-				 * Gaim doesn't know how to handle "chunked", so should always send
-				 * the Host header regardless, to get around some observed problems
-				 */
-				g_snprintf(buf, sizeof(buf),
-					"GET %s%s HTTP/%s\r\n"
-					"Connection: close\r\n"
-					"User-Agent: %s\r\n"
-					"Host: %s\r\n\r\n",
-					(gfud->full ? "" : "/"),
-					(gfud->full ? gfud->url : gfud->website.page),
-					(gfud->http11 ? "1.1" : "1.0"),
-					gfud->user_agent, gfud->website.address);
-			} else {
-				g_snprintf(buf, sizeof(buf),
-					"GET %s%s HTTP/%s\r\n"
-					"Connection: close\r\n"
-					"Host: %s\r\n\r\n",
-					(gfud->full ? "" : "/"),
-					(gfud->full ? gfud->url : gfud->website.page),
-					(gfud->http11 ? "1.1" : "1.0"),
-					gfud->website.address);
-			}
-			send = buf;
-		}
-
-		gaim_debug_misc("gaim_url_fetch", "Request: %s\n", send);
-
-		write(sock, send, strlen(send));
-		fcntl(sock, F_SETFL, O_NONBLOCK);
-		gfud->sentreq = TRUE;
-		gfud->inpa = gaim_input_add(sock, GAIM_INPUT_READ,
-			url_fetched_cb, url_data);
-		gfud->data_len = 4096;
-		gfud->webdata = g_malloc(gfud->data_len);
-
-		return;
-	}
-
-	while ((len = read(sock, buf, sizeof(buf))) > 0)
-	{
+	while((len = read(sock, buf, sizeof(buf))) > 0) {
 		/* If we've filled up our butfer, make it bigger */
-		if ((gfud->len + len) >= gfud->data_len)
-		{
-			gfud->data_len += MAX(((gfud->data_len) / 2), sizeof(buf));
+		if((gfud->len + len) >= gfud->data_len) {
+			while((gfud->len + len) >= gfud->data_len)
+				gfud->data_len += sizeof(buf);
 
 			gfud->webdata = g_realloc(gfud->webdata, gfud->data_len);
 		}
@@ -3303,12 +3245,11 @@
 
 		gfud->webdata[gfud->len] = '\0';
 
-		if (!gfud->startsaving)
-		{
+		if(!gfud->got_headers) {
 			char *tmp;
 
 			/** See if we've reached the end of the headers yet */
-			if ((tmp = strstr(gfud->webdata, "\r\n\r\n"))) {
+			if((tmp = strstr(gfud->webdata, "\r\n\r\n"))) {
 				char * new_data;
 				guint header_len = (tmp + 4 - gfud->webdata);
 				size_t content_len, body_len = 0;
@@ -3320,7 +3261,7 @@
 				if (parse_redirect(gfud->webdata, header_len, sock, gfud))
 					return;
 
-				gfud->startsaving = TRUE;
+				gfud->got_headers = TRUE;
 
 				/* No redirect. See if we can find a content length. */
 				content_len = parse_content_len(gfud->webdata, header_len);
@@ -3383,9 +3324,8 @@
 		}
 	}
 
-	if (len <= 0) {
-		if (errno == EWOULDBLOCK) {
-			errno = 0;
+	if(len <= 0) {
+		if(errno == EAGAIN) {
 			return;
 		} else if (errno != ETIMEDOUT) {
 			got_eof = TRUE;
@@ -3414,6 +3354,76 @@
 	}
 }
 
+static void
+url_fetch_connect_cb(gpointer url_data, gint sock, GaimInputCondition cond) {
+	GaimFetchUrlData *gfud = url_data;
+	int len, total_len;
+
+	if(sock == -1) {
+		gfud->callback(gfud->user_data, NULL, 0);
+		destroy_fetch_url_data(gfud);
+		return;
+	}
+
+	if (!gfud->request) {
+		if (gfud->user_agent) {
+			/* Host header is not forbidden in HTTP/1.0 requests, and HTTP/1.1
+			 * clients must know how to handle the "chunked" transfer encoding.
+			 * Gaim doesn't know how to handle "chunked", so should always send
+			 * the Host header regardless, to get around some observed problems
+			 */
+			gfud->request = g_strdup_printf(
+				"GET %s%s HTTP/%s\r\n"
+				"Connection: close\r\n"
+				"User-Agent: %s\r\n"
+				"Host: %s\r\n\r\n",
+				(gfud->full ? "" : "/"),
+				(gfud->full ? gfud->url : gfud->website.page),
+				(gfud->http11 ? "1.1" : "1.0"),
+				gfud->user_agent, gfud->website.address);
+		} else {
+			gfud->request = g_strdup_printf(
+				"GET %s%s HTTP/%s\r\n"
+				"Connection: close\r\n"
+				"Host: %s\r\n\r\n",
+				(gfud->full ? "" : "/"),
+				(gfud->full ? gfud->url : gfud->website.page),
+				(gfud->http11 ? "1.1" : "1.0"),
+				gfud->website.address);
+		}
+	}
+
+	gaim_debug_misc("gaim_url_fetch", "Request: '%s'\n", gfud->request);
+
+	if(!gfud->inpa)
+		gfud->inpa = gaim_input_add(sock, GAIM_INPUT_WRITE,
+			url_fetch_connect_cb, gfud);
+
+	total_len = strlen(gfud->request);
+
+	len = write(sock, gfud->request + gfud->request_written,
+			total_len - gfud->request_written);
+
+	if(len < 0 && errno == EAGAIN)
+		return;
+	else if(len < 0) {
+		gaim_input_remove(gfud->inpa);
+		close(sock);
+		gfud->callback(gfud->user_data, NULL, 0);
+		destroy_fetch_url_data(gfud);
+		return;
+	}
+	gfud->request_written += len;
+
+	if(gfud->request_written != total_len)
+		return;
+
+	gaim_input_remove(gfud->inpa);
+
+	gfud->inpa = gaim_input_add(sock, GAIM_INPUT_READ, url_fetched_cb,
+		gfud);
+}
+
 void
 gaim_url_fetch_request(const char *url, gboolean full,
 		const char *user_agent, gboolean http11,
@@ -3444,9 +3454,7 @@
 				   &gfud->website.page, &gfud->website.user, &gfud->website.passwd);
 
 	if (gaim_proxy_connect(NULL, gfud->website.address,
-								   gfud->website.port, url_fetched_cb,
-								   gfud) != 0)
-	{
+		gfud->website.port, url_fetch_connect_cb, gfud) != 0) {
 		destroy_fetch_url_data(gfud);
 
 		cb(user_data, g_strdup(_("g003: Error opening connection.\n")), 0);
@@ -3731,7 +3739,7 @@
 		gunichar wc = g_utf8_get_char(str);
 
 		/* super simple check. hopefully not too wrong. */
-		if(wc >= 0x80) { 
+		if(wc >= 0x80) {
 			g_string_append_printf(out, "&#%u;", (guint32) wc);
 		} else {
 			g_string_append_unichar(out, wc);
@@ -3757,12 +3765,12 @@
 	while( (b = strstr(buf, "&#")) ) {
 		gunichar wc;
 		int base = 0;
-    
+
 		/* append everything leading up to the &# */
 		g_string_append_len(out, buf, b-buf);
 
 		b += 2; /* skip past the &# */
-    
+
 		/* strtoul will handle 0x prefix as hex, but not x */
 		if(*b == 'x' || *b == 'X')
 			base = 16;
@@ -3815,7 +3823,7 @@
 }
 
 /* previously conversation::find_nick() */
-gboolean 
+gboolean
 gaim_utf8_has_word(const char *haystack, const char *needle)
 {
 	char *hay, *pin, *p;