[libsoup/new-io] Add first experiment of directory loader for files



commit 58b76c79118f0b58b6a272faa5a729b18f04465b
Author: Benjamin Otte <otte gnome org>
Date:   Sun Dec 20 18:27:56 2009 +0100

    Add first experiment of directory loader for files

 libsoup/Makefile.am                   |    4 +-
 libsoup/soup-directory-input-stream.c |  179 +++++++++++++++++++++++++++++++++
 libsoup/soup-directory-input-stream.h |   44 ++++++++
 libsoup/soup-request-file.c           |  121 +++++++++-------------
 4 files changed, 277 insertions(+), 71 deletions(-)
---
diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am
index 9f4bb13..b4cab41 100644
--- a/libsoup/Makefile.am
+++ b/libsoup/Makefile.am
@@ -136,6 +136,8 @@ libsoup_2_4_la_SOURCES =		\
 	soup-cookie-jar.c		\
 	soup-cookie-jar-text.c		\
 	soup-date.c			\
+	soup-directory-input-stream.h	\
+	soup-directory-input-stream.c	\
 	soup-form.c			\
 	soup-ftp-connection.h		\
 	soup-ftp-connection.c		\
@@ -222,4 +224,4 @@ endif
 EXTRA_DIST=				\
 	soup-marshal.list		\
 	soup-enum-types.h.tmpl		\
-	soup-enum-types.c.tmpl
\ No newline at end of file
+	soup-enum-types.c.tmpl
diff --git a/libsoup/soup-directory-input-stream.c b/libsoup/soup-directory-input-stream.c
new file mode 100644
index 0000000..48fcfd0
--- /dev/null
+++ b/libsoup/soup-directory-input-stream.c
@@ -0,0 +1,179 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-cookie-stream.c
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "soup-directory-input-stream.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "soup-message-body.h"
+
+
+#define INIT_STRING "<html><head><title>OMG!</title></head><body><table>"
+#define EXIT_STRING "</table></html>"
+
+G_DEFINE_TYPE (SoupDirectoryInputStream, soup_directory_input_stream, G_TYPE_INPUT_STREAM)
+
+static SoupBuffer *
+soup_directory_input_stream_parse_info (SoupDirectoryInputStream *stream,
+                                        GFileInfo                *info)
+{
+        SoupBuffer *buffer;
+        GString *string;
+        const char *s;
+        char *escaped, *xml_string;
+
+        if (!g_file_info_get_name (info))
+                return NULL;
+
+        string = g_string_new ("<tr>");
+        s = g_file_info_get_display_name (info);
+        if (!s) {
+                s = g_file_info_get_name (info);
+                /* FIXME: convert somehow */
+                if (!g_utf8_validate (s, -1, NULL))
+                        s = "Invalid filename";
+        }
+        escaped = g_uri_escape_string (s, NULL, FALSE);
+        xml_string = g_markup_escape_text (g_file_info_get_display_name (info), -1);
+        g_string_append_printf (string, "<td><a href=\"%s\">%s</a></td>", escaped, xml_string);
+        g_free (escaped);
+        g_free (xml_string);
+        g_string_append (string, "</tr>");
+
+        buffer = soup_buffer_new (SOUP_MEMORY_TAKE, string->str, string->len);
+        g_string_free (string, FALSE);
+
+        return buffer;
+}
+
+static SoupBuffer *
+soup_directory_input_stream_read_next_file (SoupDirectoryInputStream  *stream,
+                                            GCancellable              *cancellable,
+                                            GError                   **error)
+{
+        GFileInfo *info;
+        SoupBuffer *buffer;
+        GError *err = NULL;
+
+        do {
+                info = g_file_enumerator_next_file (stream->enumerator, cancellable, &err);
+                if (info == NULL) {
+                      if (err) {
+                              g_propagate_error (error, err);
+                              return NULL;
+                      } else if (!stream->done) {
+                              stream->done = TRUE;
+                              return soup_buffer_new (SOUP_MEMORY_STATIC,
+                                                      EXIT_STRING,
+                                                      sizeof (EXIT_STRING));
+                      } else {
+                              return NULL;
+                      }
+                }
+
+                buffer = soup_directory_input_stream_parse_info (stream, info);
+        } while (buffer == NULL);
+
+        return buffer;
+}
+
+static gssize
+soup_directory_input_stream_read (GInputStream  *input,
+                                  void          *buffer,
+                                  gsize          count,
+                                  GCancellable  *cancellable,
+                                  GError       **error)
+{
+	SoupDirectoryInputStream *stream = SOUP_DIRECTORY_INPUT_STREAM (input);
+        gssize total, size;
+        
+        for (total = 0; total < count; total += size) {
+                if (stream->buffer == NULL) {
+                        stream->buffer = soup_directory_input_stream_read_next_file (stream, cancellable, error);
+                        if (stream->buffer == NULL) {
+                                /* FIXME: Is this correct or should we forward the error? */
+                                if (total)
+                                        g_clear_error (error);
+                                return total;
+                        }
+                }
+
+                size = MIN (stream->buffer->length, count - total);
+                memcpy ((char *) buffer + total, stream->buffer->data, size);
+                if (size == stream->buffer->length) {
+                        soup_buffer_free (stream->buffer);
+                        stream->buffer = NULL;
+                } else {
+                        SoupBuffer *sub = soup_buffer_new_subbuffer (stream->buffer,
+                                                                     size,
+                                                                     stream->buffer->length - size);
+                        soup_buffer_free (stream->buffer);
+                        stream->buffer = sub;
+                }
+        }
+
+        return total;
+}
+
+static gboolean
+soup_directory_input_stream_close (GInputStream  *input,
+                                   GCancellable  *cancellable,
+                                   GError       **error)
+{
+	SoupDirectoryInputStream *stream = SOUP_DIRECTORY_INPUT_STREAM (input);
+        gboolean result;
+        
+        if (stream->buffer) {
+                soup_buffer_free (stream->buffer);
+                stream->buffer = NULL;
+        }
+
+        result = g_file_enumerator_close (stream->enumerator,
+                                          cancellable,
+                                          error);
+        g_object_unref (stream->enumerator);
+        stream->enumerator = NULL;
+
+        return result;
+}
+
+static void
+soup_directory_input_stream_class_init (SoupDirectoryInputStreamClass *stream_class)
+{
+	GInputStreamClass *inputstream_class = G_INPUT_STREAM_CLASS (stream_class);
+
+        inputstream_class->read_fn = soup_directory_input_stream_read;
+        inputstream_class->close_fn = soup_directory_input_stream_close;
+}
+
+static void
+soup_directory_input_stream_init (SoupDirectoryInputStream *stream)
+{
+        stream->buffer = soup_buffer_new (SOUP_MEMORY_STATIC,
+                                          INIT_STRING,
+                                          sizeof (INIT_STRING));
+}
+
+GInputStream *
+soup_directory_input_stream_new (GFileEnumerator *enumerator) 
+{
+	GInputStream *stream;
+        
+        g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
+
+        stream = g_object_new (SOUP_TYPE_DIRECTORY_INPUT_STREAM, NULL);
+
+        SOUP_DIRECTORY_INPUT_STREAM (stream)->enumerator = g_object_ref (enumerator);
+
+        return stream;
+}
+
diff --git a/libsoup/soup-directory-input-stream.h b/libsoup/soup-directory-input-stream.h
new file mode 100644
index 0000000..5d1040e
--- /dev/null
+++ b/libsoup/soup-directory-input-stream.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ */
+
+#ifndef SOUP_DIRECTORY_INPUT_STREAM_H
+#define SOUP_DIRECTORY_INPUT_STREAM_H 1
+
+#include <gio/gio.h>
+#include <libsoup/soup-types.h>
+#include <libsoup/soup-message-body.h>
+
+G_BEGIN_DECLS
+
+#define SOUP_TYPE_DIRECTORY_INPUT_STREAM            (soup_directory_input_stream_get_type ())
+#define SOUP_DIRECTORY_INPUT_STREAM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUP_TYPE_DIRECTORY_INPUT_STREAM, SoupDirectoryInputStream))
+#define SOUP_DIRECTORY_INPUT_STREAM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_DIRECTORY_INPUT_STREAM, SoupDirectoryInputStreamClass))
+#define SOUP_IS_DIRECTORY_INPUT_STREAM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SOUP_TYPE_DIRECTORY_INPUT_STREAM))
+#define SOUP_IS_DIRECTORY_INPUT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), SOUP_TYPE_DIRECTORY_INPUT_STREAM))
+#define SOUP_DIRECTORY_INPUT_STREAM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUP_TYPE_DIRECTORY_INPUT_STREAM, SoupDirectoryInputStreamClass))
+
+typedef struct _SoupDirectoryInputStream SoupDirectoryInputStream;
+typedef struct _SoupDirectoryInputStreamClass SoupDirectoryInputStreamClass;
+
+struct _SoupDirectoryInputStream {
+	GInputStream parent;
+
+        GFileEnumerator *enumerator;
+        SoupBuffer *buffer;
+        gboolean done;
+};
+
+struct _SoupDirectoryInputStreamClass {
+	GInputStreamClass parent_class;
+};
+
+GType          soup_directory_input_stream_get_type      (void);
+
+GInputStream * soup_directory_input_stream_new           (GFileEnumerator *enumerator);
+
+
+G_END_DECLS
+
+#endif /* SOUP_DIRECTORY_INPUT_STREAM_H */
diff --git a/libsoup/soup-request-file.c b/libsoup/soup-request-file.c
index ca8890e..13bcc6b 100644
--- a/libsoup/soup-request-file.c
+++ b/libsoup/soup-request-file.c
@@ -12,6 +12,10 @@
 #include <glib/gi18n.h>
 
 #include "soup-request-file.h"
+
+#include "soup-directory-input-stream.h"
+#include "soup-session-feature.h"
+#include "soup-session.h"
 #include "soup-uri.h"
 
 G_DEFINE_TYPE (SoupRequestFile, soup_request_file, SOUP_TYPE_REQUEST)
@@ -72,6 +76,8 @@ soup_request_file_send (SoupRequest          *request,
 			GError              **error)
 {
 	SoupRequestFile *file = SOUP_REQUEST_FILE (request);
+        GInputStream *stream;
+        GError *my_error = NULL;
 
 	file->priv->info = g_file_query_info (file->priv->gfile,
 					      G_FILE_ATTRIBUTE_STANDARD_TYPE ","
@@ -81,63 +87,47 @@ soup_request_file_send (SoupRequest          *request,
 	if (!file->priv->info)
 		return NULL;
 
-	return (GInputStream *)g_file_read (file->priv->gfile, cancellable, error);
+	stream = G_INPUT_STREAM (g_file_read (file->priv->gfile,
+			                      cancellable, &my_error));
+        if (stream == NULL) {
+                if (g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY)) {
+                        GFileEnumerator *enumerator;
+                        g_clear_error (&my_error);
+                        enumerator = g_file_enumerate_children (file->priv->gfile,
+                                                                "*",
+                                                                G_FILE_QUERY_INFO_NONE,
+                                                                cancellable,
+                                                                error);
+                        if (enumerator) {
+                                stream = soup_directory_input_stream_new (enumerator);
+                                g_object_unref (enumerator);
+                        }
+                } else {
+                        g_propagate_error (error, my_error);
+                }
+        }
+        return stream;       
 }
 
 static void
-sent_async (GObject *source, GAsyncResult *result, gpointer user_data)
+soup_request_file_send_async_thread (GSimpleAsyncResult *res,
+                                     GObject            *object,
+                                     GCancellable       *cancellable)
 {
-	GFile *gfile = G_FILE (source);
-	SoupRequestFile *file = user_data;
-	GSimpleAsyncResult *simple;
-	GError *error = NULL;
-	GFileInputStream *istream;
-
-	simple = file->priv->simple;
-	file->priv->simple = NULL;
-	if (file->priv->cancellable) {
-		g_object_unref (file->priv->cancellable);
-		file->priv->cancellable = NULL;
-	}
-
-	istream = g_file_read_finish (gfile, result, &error);
-	if (istream)
-		g_simple_async_result_set_op_res_gpointer (simple, istream, g_object_unref);
-	else {
-		g_simple_async_result_set_from_error (simple, error);
-		g_error_free (error);
-	}
-	g_simple_async_result_complete (simple);
-	g_object_unref (simple);
-}
-
-static void
-queried_info_async (GObject *source, GAsyncResult *result, gpointer user_data)
-{
-	GFile *gfile = G_FILE (source);
-	SoupRequestFile *file = user_data;
-	GError *error = NULL;
-
-	file->priv->info = g_file_query_info_finish (gfile, result, &error);
-	if (!file->priv->info) {
-		GSimpleAsyncResult *simple;
-
-		simple = file->priv->simple;
-		file->priv->simple = NULL;
-		if (file->priv->cancellable) {
-			g_object_unref (file->priv->cancellable);
-			file->priv->cancellable = NULL;
-		}
-
-		g_simple_async_result_set_from_error (simple, error);
-		g_error_free (error);
-		g_simple_async_result_complete (simple);
-		g_object_unref (simple);
-		return;
-	}
-	
-	g_file_read_async (gfile, G_PRIORITY_DEFAULT,
-			   file->priv->cancellable, sent_async, file);
+        GInputStream *stream;
+        SoupRequest *request;
+        GError *error = NULL;
+        
+        request = SOUP_REQUEST (object);
+        
+        stream = soup_request_file_send (request, cancellable, &error);
+
+        if (stream == NULL) {
+                g_simple_async_result_set_from_error (res, error);
+                g_error_free (error);
+        } else {
+                g_simple_async_result_set_op_res_gpointer (res, stream, g_object_unref);
+        }
 }
 
 static void
@@ -146,18 +136,12 @@ soup_request_file_send_async (SoupRequest          *request,
 			      GAsyncReadyCallback   callback,
 			      gpointer              user_data)
 {
-	SoupRequestFile *file = SOUP_REQUEST_FILE (request);
+        GSimpleAsyncResult *res;
 
-	file->priv->simple = g_simple_async_result_new (G_OBJECT (request),
-							callback, user_data,
-							soup_request_file_send_async);
-	file->priv->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
-	g_file_query_info_async (file->priv->gfile,
-				 G_FILE_ATTRIBUTE_STANDARD_TYPE ","
-				 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
-				 G_FILE_ATTRIBUTE_STANDARD_SIZE,
-				 0, G_PRIORITY_DEFAULT, cancellable,
-				 queried_info_async, file);
+        res = g_simple_async_result_new (G_OBJECT (request), callback, user_data, soup_request_file_send_async);
+        
+        g_simple_async_result_run_in_thread (res, soup_request_file_send_async_thread, G_PRIORITY_DEFAULT, cancellable);
+        g_object_unref (res);
 }
 
 static GInputStream *
@@ -165,14 +149,11 @@ soup_request_file_send_finish (SoupRequest          *request,
 			       GAsyncResult         *result,
 			       GError              **error)
 {
-	GSimpleAsyncResult *simple;
+        GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
 
-	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (request), soup_request_file_send_async), NULL);
+        g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == soup_request_file_send_async);
 
-	simple = G_SIMPLE_ASYNC_RESULT (result);
-	if (g_simple_async_result_propagate_error (simple, error))
-		return NULL;
-	return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+        return g_simple_async_result_get_op_res_gpointer (simple);
 }
 
 static goffset



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