[libsoup] soup-request: Add support to handle gresource URI requests



commit cbbde758b8ea533916fe25dc25d64bac564ea09a
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Sun Aug 26 15:20:34 2012 +0200

    soup-request: Add support to handle gresource URI requests
    
    GFile already supports gresource when using g_file_new_for_uri() with a
    resource:// URI. We can add "resource" as a valid scheme for
    SoupRequestFile and make sure the GFile is created with the gresource
    URI for gresource requests.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=682721

 configure.ac                            |    3 +
 docs/reference/libsoup-2.4-sections.txt |    1 +
 libsoup/soup-request-file.c             |   12 +-
 libsoup/soup-uri.c                      |   13 ++-
 libsoup/soup-uri.h                      |   13 +-
 tests/Makefile.am                       |   29 ++-
 tests/resource-test.c                   |  296 +++++++++++++++++++++++++++++++
 tests/soup-tests.gresource.xml          |    6 +
 8 files changed, 355 insertions(+), 18 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index f094587..a6b2b70 100644
--- a/configure.ac
+++ b/configure.ac
@@ -307,6 +307,9 @@ else
 fi
 AM_CONDITIONAL(HAVE_CURL, test "$CURL" != no)
 
+GLIB_COMPILE_RESOURCES=`$PKG_CONFIG --variable glib_compile_resources gio-2.0`
+AC_SUBST(GLIB_COMPILE_RESOURCES)
+
 AC_SUBST(MISSING_REGRESSION_TEST_PACKAGES)
 AM_CONDITIONAL(MISSING_REGRESSION_TEST_PACKAGES, test -n "$MISSING_REGRESSION_TEST_PACKAGES")
 
diff --git a/docs/reference/libsoup-2.4-sections.txt b/docs/reference/libsoup-2.4-sections.txt
index 6f819c3..961e416 100644
--- a/docs/reference/libsoup-2.4-sections.txt
+++ b/docs/reference/libsoup-2.4-sections.txt
@@ -631,6 +631,7 @@ SOUP_URI_SCHEME_HTTPS
 SOUP_URI_SCHEME_DATA
 SOUP_URI_SCHEME_FILE
 SOUP_URI_SCHEME_FTP
+SOUP_URI_SCHEME_RESOURCE
 soup_uri_uses_default_port
 SOUP_URI_IS_VALID
 SOUP_URI_VALID_FOR_HTTP
diff --git a/libsoup/soup-request-file.c b/libsoup/soup-request-file.c
index 0b5638d..73d0cd8 100644
--- a/libsoup/soup-request-file.c
+++ b/libsoup/soup-request-file.c
@@ -128,7 +128,15 @@ soup_request_file_ensure_file (SoupRequestFile  *file,
 	windowsify_file_uri_path (decoded_path);
 #endif
 
-	file->priv->gfile = g_file_new_for_path (decoded_path);
+	if (uri->scheme == SOUP_URI_SCHEME_RESOURCE) {
+		char *uri_str;
+
+		uri_str = g_strdup_printf ("resource://%s", decoded_path);
+		file->priv->gfile = g_file_new_for_uri (uri_str);
+		g_free (uri_str);
+	} else
+		file->priv->gfile = g_file_new_for_path (decoded_path);
+
 	g_free (decoded_path);
 	return TRUE;
 }
@@ -250,7 +258,7 @@ soup_request_file_get_content_type (SoupRequest *request)
 	return file->priv->mime_type;
 }
 
-static const char *file_schemes[] = { "file", NULL };
+static const char *file_schemes[] = { "file", "resource", NULL };
 
 static void
 soup_request_file_class_init (SoupRequestFileClass *request_file_class)
diff --git a/libsoup/soup-uri.c b/libsoup/soup-uri.c
index 4be679d..d19290b 100644
--- a/libsoup/soup-uri.c
+++ b/libsoup/soup-uri.c
@@ -110,7 +110,7 @@ static char *uri_normalized_copy (const char *str, int length, const char *unesc
 
 gpointer _SOUP_URI_SCHEME_HTTP, _SOUP_URI_SCHEME_HTTPS;
 gpointer _SOUP_URI_SCHEME_FTP;
-gpointer _SOUP_URI_SCHEME_FILE, _SOUP_URI_SCHEME_DATA;
+gpointer _SOUP_URI_SCHEME_FILE, _SOUP_URI_SCHEME_DATA, _SOUP_URI_SCHEME_RESOURCE;
 
 static inline const char *
 soup_uri_parse_scheme (const char *scheme, int len)
@@ -119,6 +119,8 @@ soup_uri_parse_scheme (const char *scheme, int len)
 		return SOUP_URI_SCHEME_HTTP;
 	} else if (len == 5 && !g_ascii_strncasecmp (scheme, "https", len)) {
 		return SOUP_URI_SCHEME_HTTPS;
+	} else if (len == 8 && !g_ascii_strncasecmp (scheme, "resource", len)) {
+		return SOUP_URI_SCHEME_RESOURCE;
 	} else {
 		char *lower_scheme;
 
@@ -815,6 +817,15 @@ soup_uri_uses_default_port (SoupURI *uri)
  **/
 
 /**
+ * SOUP_URI_SCHEME_RESOURCE:
+ *
+ * "resource" as an interned string. This can be compared directly
+ * against the value of a #SoupURI's <structfield>scheme</structfield>
+ *
+ * Since: 2.42
+ **/
+
+/**
  * soup_uri_get_scheme:
  * @uri: a #SoupURI
  *
diff --git a/libsoup/soup-uri.h b/libsoup/soup-uri.h
index b851dbe..e2195b1 100644
--- a/libsoup/soup-uri.h
+++ b/libsoup/soup-uri.h
@@ -31,14 +31,15 @@ struct _SoupURI {
 GType       soup_uri_get_type              (void);
 #define SOUP_TYPE_URI (soup_uri_get_type ())
 
-#define SOUP_URI_SCHEME_HTTP  _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_HTTP, "http")
-#define SOUP_URI_SCHEME_HTTPS _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_HTTPS, "https")
-#define SOUP_URI_SCHEME_FTP   _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_FTP, "ftp")
-#define SOUP_URI_SCHEME_FILE  _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_FILE, "file")
-#define SOUP_URI_SCHEME_DATA  _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_DATA, "data")
+#define SOUP_URI_SCHEME_HTTP     _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_HTTP, "http")
+#define SOUP_URI_SCHEME_HTTPS    _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_HTTPS, "https")
+#define SOUP_URI_SCHEME_FTP      _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_FTP, "ftp")
+#define SOUP_URI_SCHEME_FILE     _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_FILE, "file")
+#define SOUP_URI_SCHEME_DATA     _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_DATA, "data")
+#define SOUP_URI_SCHEME_RESOURCE _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_RESOURCE, "resource")
 extern gpointer _SOUP_URI_SCHEME_HTTP, _SOUP_URI_SCHEME_HTTPS;
 extern gpointer _SOUP_URI_SCHEME_FTP;
-extern gpointer _SOUP_URI_SCHEME_FILE, _SOUP_URI_SCHEME_DATA;
+extern gpointer _SOUP_URI_SCHEME_FILE, _SOUP_URI_SCHEME_DATA, _SOUP_URI_SCHEME_RESOURCE;
 
 SoupURI	   *soup_uri_new_with_base         (SoupURI    *base,
 					    const char *uri_string);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d2a1cd6..085a81b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -28,6 +28,7 @@ noinst_PROGRAMS =	\
 	ntlm-test	\
 	redirect-test	\
 	requester-test	\
+	resource-test	\
 	simple-httpd	\
 	simple-proxy	\
 	sniffing-test   \
@@ -41,6 +42,8 @@ noinst_PROGRAMS =	\
 	$(APACHE_TESTS) \
 	$(XMLRPC_TESTS)
 
+noinst_DATA = soup-tests.gresource
+
 TEST_SRCS = test-utils.c test-utils.h
 
 auth_test_SOURCES = auth-test.c $(TEST_SRCS)
@@ -66,6 +69,7 @@ pull_api_SOURCES = pull-api.c $(TEST_SRCS)
 range_test_SOURCES = range-test.c $(TEST_SRCS)
 redirect_test_SOURCES = redirect-test.c $(TEST_SRCS)
 requester_test_SOURCES = requester-test.c $(TEST_SRCS)
+resource_test_SOURCES = resource-test.c $(TEST_SRCS)
 server_auth_test_SOURCES = server-auth-test.c $(TEST_SRCS)
 simple_httpd_SOURCES = simple-httpd.c
 simple_proxy_SOURCES = simple-proxy.c
@@ -89,6 +93,9 @@ if HAVE_XMLRPC_EPI_PHP
 XMLRPC_TESTS = xmlrpc-test xmlrpc-server-test
 endif
 
+soup-tests.gresource: soup-tests.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies $(srcdir)/soup-tests.gresource.xml)
+	$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir)  $<
+
 TESTS =			\
 	chunk-test	\
 	coding-test	\
@@ -103,6 +110,7 @@ TESTS =			\
 	ntlm-test	\
 	redirect-test	\
 	requester-test	\
+	resource-test	\
 	sniffing-test	\
 	socket-test	\
 	ssl-test	\
@@ -127,17 +135,20 @@ RESOURCES =			\
 	resources/test.html	\
 	resources/text_binary.txt
 
-EXTRA_DIST =			\
-	htdigest		\
-	htpasswd		\
-	httpd.conf.in		\
-	index.txt		\
-	libsoup.supp		\
-	test-cert.pem		\
-	test-key.pem		\
-	xmlrpc-server.php	\
+EXTRA_DIST =			 \
+	htdigest		 \
+	htpasswd		 \
+	httpd.conf.in		 \
+	index.txt		 \
+	libsoup.supp		 \
+	soup-tests.gresource.xml \
+	test-cert.pem		 \
+	test-key.pem		 \
+	xmlrpc-server.php	 \
 	$(RESOURCES)
 
+DISTCLEANFILES = soup-tests.gresource
+
 if MISSING_REGRESSION_TEST_PACKAGES
 check-local: check-TESTS
 	@echo ""
diff --git a/tests/resource-test.c b/tests/resource-test.c
new file mode 100644
index 0000000..449820a
--- /dev/null
+++ b/tests/resource-test.c
@@ -0,0 +1,296 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2012 Igalia S.L.
+ */
+
+#include "test-utils.h"
+
+SoupBuffer *index_buffer;
+
+static void
+get_index (void)
+{
+	char *contents;
+	gsize length;
+	GError *error = NULL;
+
+	if (!g_file_get_contents (SRCDIR "/index.txt", &contents, &length, &error)) {
+		g_printerr ("Could not read index.txt: %s\n",
+			    error->message);
+		exit (1);
+	}
+
+	index_buffer = soup_buffer_new (SOUP_MEMORY_TAKE, contents, length);
+}
+
+static void
+register_gresource (void)
+{
+	GResource *resource;
+	GError *error = NULL;
+
+	resource = g_resource_load ("soup-tests.gresource", &error);
+	if (!resource) {
+		g_printerr ("Could not load resource soup-tests.gresource: %s\n",
+			    error->message);
+		exit (1);
+	}
+	g_resources_register (resource);
+	g_resource_unref (resource);
+}
+
+static void
+check_results (GString *body)
+{
+	if (body->len != index_buffer->length) {
+		debug_printf (1, "    body length mismatch: expected %d, got %d\n",
+			      (int)index_buffer->length, (int)body->len);
+		errors++;
+	} else if (memcmp (body->str, index_buffer->data, body->len) != 0) {
+		debug_printf (1, "    body data mismatch\n");
+		errors++;
+	}
+}
+
+typedef struct {
+	GString *body;
+	char buffer[1024];
+	GMainLoop *loop;
+} AsyncRequestData;
+
+static void
+stream_closed (GObject *source, GAsyncResult *result, gpointer user_data)
+{
+	GInputStream *in = G_INPUT_STREAM (source);
+	AsyncRequestData *data = user_data;
+	GError *error = NULL;
+
+	if (!g_input_stream_close_finish (in, result, &error)) {
+		debug_printf (1, "    close failed: %s\n", error->message);
+		g_error_free (error);
+		errors++;
+	}
+	g_main_loop_quit (data->loop);
+	g_object_unref (in);
+}
+
+static void
+test_read_ready (GObject *source, GAsyncResult *result, gpointer user_data)
+{
+	GInputStream *in = G_INPUT_STREAM (source);
+	AsyncRequestData *data = user_data;
+	gssize nread;
+	GError *error = NULL;
+
+	nread = g_input_stream_read_finish (in, result, &error);
+	if (nread == -1) {
+		debug_printf (1, "    g_input_stream_read failed: %s\n",
+			      error->message);
+		g_clear_error (&error);
+		g_input_stream_close (in, NULL, NULL);
+		g_object_unref (in);
+		errors++;
+		return;
+	} else if (nread == 0) {
+		g_input_stream_close_async (in, G_PRIORITY_DEFAULT, NULL,
+					    stream_closed, data);
+		return;
+	}
+
+	g_string_append_len (data->body, data->buffer, nread);
+	g_input_stream_read_async (in, data->buffer, sizeof (data->buffer),
+				   G_PRIORITY_DEFAULT, NULL,
+				   test_read_ready, data);
+}
+
+static void
+async_request_sent (GObject *source, GAsyncResult *result, gpointer user_data)
+{
+	GInputStream *in;
+	AsyncRequestData *data = user_data;
+	GError *error = NULL;
+
+	in = soup_request_send_finish (SOUP_REQUEST (source), result, &error);
+	if (!in) {
+		debug_printf (1, "    soup_request_send_async failed: %s\n",
+			      error->message);
+		g_clear_error (&error);
+		errors++;
+		return;
+	}
+
+	g_input_stream_read_async (in, data->buffer, sizeof (data->buffer),
+				   G_PRIORITY_DEFAULT, NULL,
+				   test_read_ready, data);
+}
+
+static void
+do_async_request (SoupRequest *request)
+{
+	AsyncRequestData data;
+
+	data.body = g_string_new (NULL);
+	soup_request_send_async (request, NULL, async_request_sent, &data);
+
+	data.loop = g_main_loop_new (soup_session_get_async_context (soup_request_get_session (request)), TRUE);
+	g_main_loop_run (data.loop);
+	g_main_loop_unref (data.loop);
+
+	check_results (data.body);
+	g_string_free (data.body, TRUE);
+}
+
+static void
+do_sync_request (SoupRequest *request)
+{
+	GInputStream *in;
+	GString *body;
+	char buffer[1024];
+	gssize nread;
+	GError *error = NULL;
+
+	in = soup_request_send (request, NULL, &error);
+	if (!in) {
+		debug_printf (1, "    soup_request_send failed: %s\n",
+			      error->message);
+		g_clear_error (&error);
+		errors++;
+		return;
+	}
+
+	body = g_string_new (NULL);
+	do {
+		nread = g_input_stream_read (in, buffer, sizeof (buffer),
+					     NULL, &error);
+		if (nread == -1) {
+			debug_printf (1, "    g_input_stream_read failed: %s\n",
+				      error->message);
+			g_clear_error (&error);
+			errors++;
+			break;
+		}
+		g_string_append_len (body, buffer, nread);
+	} while (nread > 0);
+
+	if (!g_input_stream_close (in, NULL, &error)) {
+		debug_printf (1, "    g_input_stream_close failed: %s\n",
+			      error->message);
+		g_clear_error (&error);
+		errors++;
+	}
+	g_object_unref (in);
+
+	check_results (body);
+	g_string_free (body, TRUE);
+}
+
+static void
+do_request_file_test (SoupRequester *requester,
+		      gboolean	     async)
+{
+	SoupRequest *request;
+	GFile *index;
+	char *uri_string;
+	SoupURI *uri;
+
+	index = g_file_new_for_path (SRCDIR "/index.txt");
+	uri_string = g_file_get_uri (index);
+	g_object_unref (index);
+
+	uri = soup_uri_new (uri_string);
+	g_free (uri_string);
+
+	request = soup_requester_request_uri (requester, uri, NULL);
+	if (async)
+		do_async_request (request);
+	else
+		do_sync_request (request);
+	g_object_unref (request);
+
+	soup_uri_free (uri);
+}
+
+static void
+do_request_data_test (SoupRequester *requester,
+		      gboolean	     async)
+{
+	SoupRequest *request;
+	gchar *base64;
+	char *uri_string;
+	SoupURI *uri;
+
+	base64 = g_base64_encode ((const guchar *)index_buffer->data, index_buffer->length);
+	uri_string = g_strdup_printf ("data:text/plain;charset=utf8;base64,%s", base64);
+	g_free (base64);
+
+	uri = soup_uri_new (uri_string);
+	g_free (uri_string);
+
+	request = soup_requester_request_uri (requester, uri, NULL);
+	if (async)
+		do_async_request (request);
+	else
+		do_sync_request (request);
+	g_object_unref (request);
+
+	soup_uri_free (uri);
+}
+
+static void
+do_request_gresource_test (SoupRequester *requester,
+			   gboolean	  async)
+{
+	SoupRequest *request;
+	SoupURI *uri;
+
+	uri = soup_uri_new ("resource:///org/gnome/libsoup/tests/index.txt");
+	request = soup_requester_request_uri (requester, uri, NULL);
+	if (async)
+		do_async_request (request);
+	else
+		do_sync_request (request);
+	g_object_unref (request);
+
+	soup_uri_free (uri);
+}
+
+int
+main (int argc, char **argv)
+{
+	SoupSession *session;
+	SoupRequester *requester;
+
+	test_init (argc, argv, NULL);
+
+	get_index ();
+	register_gresource ();
+
+	/* Sync tests */
+	session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
+	requester = soup_requester_new ();
+	soup_session_add_feature (session, SOUP_SESSION_FEATURE (requester));
+	g_object_unref (requester);
+
+	do_request_file_test (requester, FALSE);
+	do_request_data_test (requester, FALSE);
+	do_request_gresource_test (requester, FALSE);
+
+	soup_test_session_abort_unref (session);
+
+	/* Async tests */
+	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
+					 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
+					 NULL);
+	requester = soup_requester_new ();
+	soup_session_add_feature (session, SOUP_SESSION_FEATURE (requester));
+	g_object_unref (requester);
+
+	do_request_file_test (requester, TRUE);
+	do_request_data_test (requester, TRUE);
+	do_request_gresource_test (requester, TRUE);
+
+	soup_test_session_abort_unref (session);
+
+	test_cleanup ();
+	return errors != 0;
+}
diff --git a/tests/soup-tests.gresource.xml b/tests/soup-tests.gresource.xml
new file mode 100644
index 0000000..969a6bf
--- /dev/null
+++ b/tests/soup-tests.gresource.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/org/gnome/libsoup/tests">
+    <file>index.txt</file>
+  </gresource>
+</gresources>
\ No newline at end of file



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