libsoup r1181 - in trunk: . libsoup tests



Author: danw
Date: Fri Oct 10 21:35:35 2008
New Revision: 1181
URL: http://svn.gnome.org/viewvc/libsoup?rev=1181&view=rev

Log:
	* libsoup/soup-message-headers.c
	(soup_message_headers_get_ranges): if the caller passed the
	total_length of the message body, then sort sort the ranges and
	merge overlapping ones to generate a minimal set.

	* tests/range-test.c: test it


Modified:
   trunk/ChangeLog
   trunk/libsoup/soup-message-headers.c
   trunk/tests/range-test.c

Modified: trunk/libsoup/soup-message-headers.c
==============================================================================
--- trunk/libsoup/soup-message-headers.c	(original)
+++ trunk/libsoup/soup-message-headers.c	Fri Oct 10 21:35:35 2008
@@ -682,6 +682,15 @@
  * (Eg, the last 500 bytes would be @start = %-500 and @end = %-1.)
  **/
 
+static int
+sort_ranges (gconstpointer a, gconstpointer b)
+{
+	SoupRange *ra = (SoupRange *)a;
+	SoupRange *rb = (SoupRange *)b;
+
+	return ra->start - rb->start;
+}
+
 /**
  * soup_message_headers_get_ranges:
  * @hdrs: a #SoupMessageHeaders
@@ -694,9 +703,11 @@
  * soup_message_headers_free_ranges().
  *
  * If @total_length is non-0, its value will be used to adjust the
- * returned ranges to have explicit start and end values. If
+ * returned ranges to have explicit start and end values, and the
+ * returned ranges will be sorted and non-overlapping. If
  * @total_length is 0, then some ranges may have an end value of -1,
- * as described under #SoupRange.
+ * as described under #SoupRange, and some of the ranges may be
+ * redundant.
  *
  * Return value: %TRUE if @hdrs contained a "Range" header containing
  * byte ranges which could be parsed, %FALSE otherwise (in which case
@@ -713,6 +724,7 @@
 	GArray *array;
 	SoupRange cur;
 	char *spec, *end;
+	int i;
 
 	if (!range || strncmp (range, "bytes", 5) != 0)
 		return FALSE;
@@ -754,8 +766,23 @@
 	}
 
 	soup_header_free_list (range_list);
+
+	if (total_length) {
+		g_array_sort (array, sort_ranges);
+		for (i = 1; i < array->len; i++) {
+			SoupRange *cur = &((SoupRange *)array->data)[i];
+			SoupRange *prev = &((SoupRange *)array->data)[i - 1];
+
+			if (cur->start <= prev->end) {
+				prev->end = MAX (prev->end, cur->end);
+				g_array_remove_index (array, i);
+			}
+		}
+	}
+
 	*ranges = (SoupRange *)array->data;
 	*length = array->len;
+
 	g_array_free (array, FALSE);
 	return TRUE;
 }

Modified: trunk/tests/range-test.c
==============================================================================
--- trunk/tests/range-test.c	(original)
+++ trunk/tests/range-test.c	Fri Oct 10 21:35:35 2008
@@ -85,13 +85,10 @@
 }
 
 static void
-request_single_range (SoupSession *session, char *uri,
-		      int start, int end)
+do_single_range (SoupSession *session, SoupMessage *msg,
+		 int start, int end)
 {
-	SoupMessage *msg;
-
-	msg = soup_message_new ("GET", uri);
-	soup_message_headers_set_range (msg->request_headers, start, end);
+	const char *content_type;
 
 	debug_printf (1, "    Range: %s\n",
 		      soup_message_headers_get (msg->request_headers, "Range"));
@@ -106,13 +103,34 @@
 		return;
 	}
 
+	content_type = soup_message_headers_get_content_type (
+		msg->response_headers, NULL);
+	if (content_type && !strcmp (content_type, "multipart/byteranges")) {
+		debug_printf (1, "    Response body should not have been multipart/byteranges\n");
+		g_object_unref (msg);
+		errors++;
+		return;
+	}
+
 	check_part (msg->response_headers, msg->response_body->data,
 		    msg->response_body->length, TRUE, start, end);
 	g_object_unref (msg);
 }
 
 static void
-request_multi_range (SoupSession *session, SoupMessage *msg)
+request_single_range (SoupSession *session, char *uri,
+		      int start, int end)
+{
+	SoupMessage *msg;
+
+	msg = soup_message_new ("GET", uri);
+	soup_message_headers_set_range (msg->request_headers, start, end);
+	do_single_range (session, msg, start, end);
+}
+
+static void
+do_multi_range (SoupSession *session, SoupMessage *msg,
+		int expected_return_ranges)
 {
 	SoupMultipart *multipart;
 	const char *content_type;
@@ -150,6 +168,12 @@
 	}
 
 	length = soup_multipart_get_length (multipart);
+	if (length != expected_return_ranges) {
+		debug_printf (1, "    Expected %d ranges, got %d\n",
+			      expected_return_ranges, length);
+		errors++;
+	}
+
 	for (i = 0; i < length; i++) {
 		SoupMessageHeaders *headers;
 		SoupBuffer *body;
@@ -166,7 +190,8 @@
 static void
 request_double_range (SoupSession *session, char *uri,
 		      int first_start, int first_end,
-		      int second_start, int second_end)
+		      int second_start, int second_end,
+		      int expected_return_ranges)
 {
 	SoupMessage *msg;
 	SoupRange ranges[2];
@@ -178,14 +203,20 @@
 	ranges[1].end = second_end;
 	soup_message_headers_set_ranges (msg->request_headers, ranges, 2);
 
-	request_multi_range (session, msg);
+	if (expected_return_ranges == 1) {
+		do_single_range (session, msg,
+				 MIN (first_start, second_start),
+				 MAX (first_end, second_end));
+	} else
+		do_multi_range (session, msg, expected_return_ranges);
 }
 
 static void
 request_triple_range (SoupSession *session, char *uri,
 		      int first_start, int first_end,
 		      int second_start, int second_end,
-		      int third_start, int third_end)
+		      int third_start, int third_end,
+		      int expected_return_ranges)
 {
 	SoupMessage *msg;
 	SoupRange ranges[3];
@@ -199,46 +230,96 @@
 	ranges[2].end = third_end;
 	soup_message_headers_set_ranges (msg->request_headers, ranges, 3);
 
-	request_multi_range (session, msg);
+	if (expected_return_ranges == 1) {
+		do_single_range (session, msg,
+				 MIN (first_start, MIN (second_start, third_start)),
+				 MAX (first_end, MAX (second_end, third_end)));
+	} else
+		do_multi_range (session, msg, expected_return_ranges);
 }
 
 static void
-do_range_test (SoupSession *session, char *uri)
+do_range_test (SoupSession *session, char *uri, gboolean expect_coalesce)
 {
-	int sevenths = full_response->length / 7;
+	int twelfths = full_response->length / 12;
 
 	memset (test_response, 0, full_response->length);
 
-	debug_printf (1, "Requesting %d-%d\n", 0 * sevenths, 1 * sevenths);
+	/* We divide the response into 12 ranges and request them
+	 * as follows:
+	 *
+	 *  0: A (first single request)
+	 *  1: D (2nd part of triple request)
+	 *  2: C (1st part of double request)
+	 *  3: D (1st part of triple request)
+	 *  4: F (trickier overlapping request)
+	 *  5: C (2nd part of double request)
+	 *  6: D (3rd part of triple request)
+	 *  7: E (overlapping request)
+	 *  8: E (overlapping request)
+	 *  9: F (trickier overlapping request)
+	 * 10: F (trickier overlapping request)
+	 * 11: B (second and third single requests)
+	 */
+
+	/* A: 0, simple request */
+	debug_printf (1, "Requesting %d-%d\n", 0 * twelfths, 1 * twelfths);
 	request_single_range (session, uri,
-			      0 * sevenths, 1 * sevenths);
+			      0 * twelfths, 1 * twelfths);
 
-	/* These two are redundant in terms of data coverage (except
-	 * maybe for a single byte because of rounding), but they may
-	 * still catch Range-header-generating bugs.
+	/* B: 11, end-relative request. These two are mostly redundant
+	 * in terms of data coverage, but they may still catch
+	 * Range-header-generating bugs.
 	 */
-	debug_printf (1, "Requesting %d-\n", 6 * sevenths);
+	debug_printf (1, "Requesting %d-\n", 11 * twelfths);
 	request_single_range (session, uri,
-			      6 * sevenths, -1);
-	debug_printf (1, "Requesting -%d\n", 1 * sevenths);
+			      11 * twelfths, -1);
+	debug_printf (1, "Requesting -%d\n", 1 * twelfths);
 	request_single_range (session, uri,
-			      -1 * sevenths, -1);
+			      -1 * twelfths, -1);
 
+	/* C: 2 and 5 */
 	debug_printf (1, "Requesting %d-%d,%d-%d\n",
-		      2 * sevenths, 3 * sevenths,
-		      5 * sevenths, 6 * sevenths);
+		      2 * twelfths, 3 * twelfths,
+		      5 * twelfths, 6 * twelfths);
 	request_double_range (session, uri,
-			      2 * sevenths, 3 * sevenths,
-			      5 * sevenths, 6 * sevenths);
+			      2 * twelfths, 3 * twelfths,
+			      5 * twelfths, 6 * twelfths,
+			      2);
 
+	/* D: 1, 3, 6 */
 	debug_printf (1, "Requesting %d-%d,%d-%d,%d-%d\n",
-		      3 * sevenths, 4 * sevenths,
-		      1 * sevenths, 2 * sevenths,
-		      4 * sevenths, 5 * sevenths);
+		      3 * twelfths, 4 * twelfths,
+		      1 * twelfths, 2 * twelfths,
+		      6 * twelfths, 7 * twelfths);
+	request_triple_range (session, uri,
+			      3 * twelfths, 4 * twelfths,
+			      1 * twelfths, 2 * twelfths,
+			      6 * twelfths, 7 * twelfths,
+			      3);
+
+	/* E: 7 and 8: should coalesce into a single response */
+	debug_printf (1, "Requesting %d-%d,%d-%d (can coalesce)\n",
+		      7 * twelfths, 8 * twelfths,
+		      8 * twelfths, 9 * twelfths);
+	request_double_range (session, uri,
+			      7 * twelfths, 8 * twelfths,
+			      8 * twelfths, 9 * twelfths,
+			      expect_coalesce ? 1 : 2);
+
+	/* F: 4, 9, 10: 9 and 10 should coalesce even though 4 was
+	 * requested between them. (Also, they actually overlap in
+	 * this case, as opposed to just touching.)
+	 */
+	debug_printf (1, "Requesting %d-%d,%d-%d,%d-%d (can partially coalesce)\n",
+		      9 * twelfths, 10 * twelfths + 5,
+		      4 * twelfths, 5 * twelfths,
+		      10 * twelfths - 5, 11 * twelfths);
 	request_triple_range (session, uri,
-			      3 * sevenths, 4 * sevenths,
-			      1 * sevenths, 2 * sevenths,
-			      4 * sevenths, 5 * sevenths);
+			      9 * twelfths, 10 * twelfths + 5,
+			      4 * twelfths, 5 * twelfths,
+			      10 * twelfths - 5, 11 * twelfths,
+			      expect_coalesce ? 2 : 3);
 
 	if (memcmp (full_response->data, test_response, full_response->length) != 0) {
 		debug_printf (1, "\nfull_response and test_response don't match\n");
@@ -275,14 +356,14 @@
 	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
 
 	debug_printf (1, "1. Testing against apache\n");
-	do_range_test (session, "http://localhost:47524/";);
+	do_range_test (session, "http://localhost:47524/";, FALSE);
 
 	debug_printf (1, "\n2. Testing against SoupServer\n");
 	server = soup_test_server_new (FALSE);
 	soup_server_add_handler (server, NULL, server_handler, NULL, NULL);
 	base_uri = g_strdup_printf ("http://localhost:%u/";,
 				    soup_server_get_port (server));
-	do_range_test (session, base_uri);
+	do_range_test (session, base_uri, TRUE);
 
 	soup_test_session_abort_unref (session);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]