2232 lines
65 KiB
Diff
2232 lines
65 KiB
Diff
|
commit 25cb6b442cc37b8e6056cc837233523d7572736b
|
||
|
Author: Hans Petter Jansson <hpj@cl.no>
|
||
|
Date: Thu Jan 13 18:04:58 2011 +0100
|
||
|
|
||
|
Patch 8: gvfs-dav-recursive-directory-ops.patch
|
||
|
|
||
|
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
|
||
|
index 39369b4..767eeb6 100644
|
||
|
--- a/daemon/Makefile.am
|
||
|
+++ b/daemon/Makefile.am
|
||
|
@@ -430,6 +430,7 @@ gvfsd_gphoto2_LDADD = $(libraries) $(GPHOTO2_LIBS) $(HAL_LIBS)
|
||
|
endif
|
||
|
|
||
|
gvfsd_http_SOURCES = \
|
||
|
+ gmempipe.c gmempipe.h \
|
||
|
soup-input-stream.c soup-input-stream.h \
|
||
|
soup-output-stream.c soup-output-stream.h \
|
||
|
gvfsbackendhttp.c gvfsbackendhttp.h \
|
||
|
@@ -474,6 +475,7 @@ gvfsd_nvvfs_LDADD = $(libraries)
|
||
|
|
||
|
|
||
|
gvfsd_dav_SOURCES = \
|
||
|
+ gmempipe.c gmempipe.h \
|
||
|
soup-input-stream.c soup-input-stream.h \
|
||
|
soup-output-stream.c soup-output-stream.h \
|
||
|
gvfsbackendhttp.c gvfsbackendhttp.h \
|
||
|
diff --git a/daemon/gmempipe.c b/daemon/gmempipe.c
|
||
|
new file mode 100644
|
||
|
index 0000000..3ceebd9
|
||
|
--- /dev/null
|
||
|
+++ b/daemon/gmempipe.c
|
||
|
@@ -0,0 +1,716 @@
|
||
|
+/* GIO - GLib Input, Output and Streaming Library
|
||
|
+ *
|
||
|
+ * Copyright (C) Christian Kellner <gicmo@gnome.org>
|
||
|
+ *
|
||
|
+ * This library is free software; you can redistribute it and/or
|
||
|
+ * modify it under the terms of the GNU Lesser General Public
|
||
|
+ * License as published by the Free Software Foundation; either
|
||
|
+ * version 2 of the License, or (at your option) any later version.
|
||
|
+ *
|
||
|
+ * This library is distributed in the hope that it will be useful,
|
||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
+ * Lesser General Public License for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU Lesser General
|
||
|
+ * Public License along with this library; if not, write to the
|
||
|
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||
|
+ * Boston, MA 02111-1307, USA.
|
||
|
+ *
|
||
|
+ * Author: Christian Kellner <gicmo@gnome.org>
|
||
|
+ */
|
||
|
+
|
||
|
+#include "gmempipe.h"
|
||
|
+
|
||
|
+#include <string.h>
|
||
|
+
|
||
|
+
|
||
|
+
|
||
|
+G_DEFINE_TYPE (GMemPipe, g_mem_pipe, G_TYPE_OBJECT)
|
||
|
+
|
||
|
+/* TODO: Real P_() */
|
||
|
+#define P_(_x) (_x)
|
||
|
+
|
||
|
+static void g_mem_pipe_get_property (GObject *object,
|
||
|
+ guint prop_id,
|
||
|
+ GValue *value,
|
||
|
+ GParamSpec *pspec);
|
||
|
+
|
||
|
+static void g_mem_pipe_set_property (GObject *object,
|
||
|
+ guint prop_id,
|
||
|
+ const GValue *value,
|
||
|
+ GParamSpec *pspec);
|
||
|
+
|
||
|
+typedef enum {
|
||
|
+
|
||
|
+ GPD_NONE = 0x00,
|
||
|
+ GPD_READ = 0x01, /* reading from the pipe */
|
||
|
+ GPD_WRITE = 0x02 /* writing to the pipe */
|
||
|
+
|
||
|
+} GPipeDirection;
|
||
|
+
|
||
|
+enum
|
||
|
+{
|
||
|
+ PROP_0,
|
||
|
+ PROP_BUFFER_SIZE
|
||
|
+};
|
||
|
+
|
||
|
+struct _GMemPipePrivate
|
||
|
+{
|
||
|
+
|
||
|
+ struct {
|
||
|
+ gsize size;
|
||
|
+ gsize dlen;
|
||
|
+
|
||
|
+ char *data;
|
||
|
+
|
||
|
+ } buffer;
|
||
|
+
|
||
|
+ GMutex *lock;
|
||
|
+ GCond *cond;
|
||
|
+
|
||
|
+ GPipeDirection closed;
|
||
|
+ GInputStream *input_stream;
|
||
|
+ GOutputStream *output_stream;
|
||
|
+};
|
||
|
+
|
||
|
+/* streaming classes declarations */
|
||
|
+typedef struct _GMemPipeInputStream GMemPipeInputStream;
|
||
|
+typedef struct _GMemPipeOutputStream GMemPipeOutputStream;
|
||
|
+
|
||
|
+static GOutputStream *g_mem_pipe_output_stream_new (GMemPipe *mem_pipe);
|
||
|
+static GInputStream *g_mem_pipe_input_stream_new (GMemPipe *mem_pipe);
|
||
|
+
|
||
|
+/* GMemPipe imlementation starts here*/
|
||
|
+static void
|
||
|
+g_mem_pipe_finalize (GObject *object)
|
||
|
+{
|
||
|
+ GMemPipe *mem_pipe;
|
||
|
+ GMemPipePrivate *priv;
|
||
|
+
|
||
|
+ mem_pipe = G_MEM_PIPE (object);
|
||
|
+
|
||
|
+ priv = mem_pipe->priv;
|
||
|
+
|
||
|
+ g_mutex_free (priv->lock);
|
||
|
+ g_cond_free (priv->cond);
|
||
|
+
|
||
|
+ if (priv->buffer.size)
|
||
|
+ g_free (priv->buffer.data);
|
||
|
+
|
||
|
+ /* FIXME: move those to dispose? */
|
||
|
+ g_object_unref (priv->input_stream);
|
||
|
+ g_object_unref (priv->output_stream);
|
||
|
+
|
||
|
+ if (G_OBJECT_CLASS (g_mem_pipe_parent_class)->finalize)
|
||
|
+ (*G_OBJECT_CLASS (g_mem_pipe_parent_class)->finalize) (object);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+g_mem_pipe_class_init (GMemPipeClass *klass)
|
||
|
+{
|
||
|
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||
|
+
|
||
|
+ g_type_class_add_private (klass, sizeof (GMemPipePrivate));
|
||
|
+
|
||
|
+ gobject_class->finalize = g_mem_pipe_finalize;
|
||
|
+ gobject_class->set_property = g_mem_pipe_set_property;
|
||
|
+ gobject_class->get_property = g_mem_pipe_get_property;
|
||
|
+
|
||
|
+ g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
|
||
|
+ g_param_spec_uint ("buffer-size",
|
||
|
+ P_("Buffer size"),
|
||
|
+ P_("The size of the internal buffer"),
|
||
|
+ 0,
|
||
|
+ G_MAXUINT,
|
||
|
+ 0,
|
||
|
+ G_PARAM_CONSTRUCT_ONLY |
|
||
|
+ G_PARAM_READWRITE |
|
||
|
+ G_PARAM_STATIC_STRINGS));
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+g_mem_pipe_init (GMemPipe *mem_pipe)
|
||
|
+{
|
||
|
+ GMemPipePrivate *priv;
|
||
|
+ mem_pipe->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (mem_pipe,
|
||
|
+ G_TYPE_MEM_PIPE,
|
||
|
+ GMemPipePrivate);
|
||
|
+
|
||
|
+ priv->cond = g_cond_new ();
|
||
|
+ priv->lock = g_mutex_new ();
|
||
|
+ priv->input_stream = g_mem_pipe_input_stream_new (mem_pipe);
|
||
|
+ priv->output_stream = g_mem_pipe_output_stream_new (mem_pipe);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+g_mem_pipe_get_property (GObject *object,
|
||
|
+ guint prop_id,
|
||
|
+ GValue *value,
|
||
|
+ GParamSpec *pspec)
|
||
|
+{
|
||
|
+ GMemPipe *mem_pipe = G_MEM_PIPE (object);
|
||
|
+
|
||
|
+ switch (prop_id)
|
||
|
+ {
|
||
|
+ case PROP_BUFFER_SIZE:
|
||
|
+ g_warn_if_fail (mem_pipe->priv->buffer.dlen == 0);
|
||
|
+ g_value_set_uint (value, mem_pipe->priv->buffer.size);
|
||
|
+ break;
|
||
|
+
|
||
|
+ default:
|
||
|
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+g_mem_pipe_set_property (GObject *object,
|
||
|
+ guint prop_id,
|
||
|
+ const GValue *value,
|
||
|
+ GParamSpec *pspec)
|
||
|
+{
|
||
|
+ GMemPipe *mem_pipe = G_MEM_PIPE (object);
|
||
|
+
|
||
|
+ switch (prop_id)
|
||
|
+ {
|
||
|
+ case PROP_BUFFER_SIZE:
|
||
|
+ mem_pipe->priv->buffer.size = g_value_get_uint (value);
|
||
|
+ mem_pipe->priv->buffer.data = g_realloc (mem_pipe->priv->buffer.data,
|
||
|
+ mem_pipe->priv->buffer.size);
|
||
|
+ break;
|
||
|
+
|
||
|
+ default:
|
||
|
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+signal_cancellation (GCancellable *cancellable,
|
||
|
+ gpointer user_data)
|
||
|
+{
|
||
|
+ GMemPipe *mem_pipe;
|
||
|
+ GMemPipePrivate *priv;
|
||
|
+
|
||
|
+ mem_pipe = G_MEM_PIPE (user_data);
|
||
|
+ priv = mem_pipe->priv;
|
||
|
+
|
||
|
+ g_mutex_lock (priv->lock);
|
||
|
+ g_cond_signal (priv->cond);
|
||
|
+ g_mutex_unlock (priv->lock);
|
||
|
+}
|
||
|
+
|
||
|
+static guint
|
||
|
+_g_mem_pipe_cancellable_connect (GMemPipe *mem_pipe,
|
||
|
+ GCancellable *cancellable)
|
||
|
+{
|
||
|
+ guint handler_id;
|
||
|
+
|
||
|
+ if (cancellable == NULL)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ handler_id = g_cancellable_connect (cancellable,
|
||
|
+ G_CALLBACK (signal_cancellation),
|
||
|
+ mem_pipe,
|
||
|
+ NULL);
|
||
|
+
|
||
|
+ return handler_id;
|
||
|
+}
|
||
|
+
|
||
|
+/* half open means write-end closed and read-end still open;
|
||
|
+ * NB there is no need to special case the inverse of it
|
||
|
+ * since writing to a pipe where the read is already closed
|
||
|
+ * makes no sense at all (this is a SIGPIPE in unix land)
|
||
|
+ */
|
||
|
+#define _g_mem_pipe_is_half_open(_pipe) _pipe->priv->closed & GPD_WRITE && \
|
||
|
+ ~_pipe->priv->closed & GPD_READ
|
||
|
+static gboolean
|
||
|
+_g_mem_pipe_check_is_open (GMemPipe *mem_pipe,
|
||
|
+ GPipeDirection direction,
|
||
|
+ GError **error)
|
||
|
+{
|
||
|
+ gboolean res;
|
||
|
+ GMemPipePrivate *priv = mem_pipe->priv;
|
||
|
+
|
||
|
+ res = priv->closed == 0;
|
||
|
+
|
||
|
+ if (res == FALSE && direction & GPD_READ)
|
||
|
+ res = _g_mem_pipe_is_half_open (mem_pipe);
|
||
|
+
|
||
|
+ if (res == FALSE)
|
||
|
+ g_set_error_literal (error,
|
||
|
+ G_IO_ERROR,
|
||
|
+ G_IO_ERROR_CLOSED,
|
||
|
+ "Pipe closed");
|
||
|
+ return res;
|
||
|
+}
|
||
|
+
|
||
|
+/* LOCKED: Must be called with the LOCK held!
|
||
|
+ *
|
||
|
+ * Checks if the pipe is ready for IO. Will wait
|
||
|
+ * if not.
|
||
|
+ *
|
||
|
+ * NB: Can only check for GPD_WIRTE *or* GPD_READ!
|
||
|
+ *
|
||
|
+ * Returns: The number of data one can read/write
|
||
|
+ * to the pipe; -1 in case of an error and 0 iff
|
||
|
+ * the pipe write end got closed and there is no
|
||
|
+ * data left in the pipe to read from.
|
||
|
+ */
|
||
|
+static gssize
|
||
|
+_g_mem_pipe_poll (GMemPipe *mem_pipe,
|
||
|
+ GPipeDirection direction,
|
||
|
+ GCancellable *cancellable,
|
||
|
+ GError **error)
|
||
|
+{
|
||
|
+ GMemPipePrivate *priv = mem_pipe->priv;
|
||
|
+ gssize res = -1;
|
||
|
+
|
||
|
+ while (! g_cancellable_set_error_if_cancelled (cancellable, error))
|
||
|
+ {
|
||
|
+ if (! _g_mem_pipe_check_is_open (mem_pipe, direction, error))
|
||
|
+ break;
|
||
|
+
|
||
|
+ /* First check if we have to wait at all */
|
||
|
+ if (direction & GPD_WRITE)
|
||
|
+ {
|
||
|
+ res = priv->buffer.size - priv->buffer.dlen;
|
||
|
+ g_assert (res >= 0);
|
||
|
+ }
|
||
|
+ else /* ergo: direction & GPD_READ */
|
||
|
+ {
|
||
|
+ res = priv->buffer.dlen;
|
||
|
+
|
||
|
+ /* if the pipe is half open we must
|
||
|
+ never wait even in the case that
|
||
|
+ res == 0; so we directly return */
|
||
|
+ if (_g_mem_pipe_is_half_open (mem_pipe))
|
||
|
+ return res;
|
||
|
+ }
|
||
|
+ /* if we got some data (or error) there is no need to wait! */
|
||
|
+ if (res != 0)
|
||
|
+ break;
|
||
|
+
|
||
|
+ g_cond_wait (priv->cond, priv->lock);
|
||
|
+
|
||
|
+ res = -1; /* reset */
|
||
|
+ }
|
||
|
+
|
||
|
+ return res;
|
||
|
+}
|
||
|
+
|
||
|
+gssize
|
||
|
+g_mem_pipe_read (GMemPipe *mem_pipe,
|
||
|
+ void *buffer,
|
||
|
+ gsize count,
|
||
|
+ GCancellable *cancellable,
|
||
|
+ GError **error)
|
||
|
+{
|
||
|
+ GMemPipePrivate *priv;
|
||
|
+ gssize n;
|
||
|
+ gssize nread;
|
||
|
+ gboolean is_buffered;
|
||
|
+ gulong handler_id;
|
||
|
+
|
||
|
+ g_return_val_if_fail (G_IS_MEM_PIPE (mem_pipe), -1);
|
||
|
+ priv = mem_pipe->priv;
|
||
|
+
|
||
|
+ if (count == 0)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ handler_id = _g_mem_pipe_cancellable_connect (mem_pipe, cancellable);
|
||
|
+ g_mutex_lock (priv->lock);
|
||
|
+
|
||
|
+ is_buffered = (priv->buffer.size != 0);
|
||
|
+ if (is_buffered == FALSE)
|
||
|
+ {
|
||
|
+ priv->buffer.data = buffer;
|
||
|
+ priv->buffer.size = count;
|
||
|
+
|
||
|
+ /* if the writer thread is waiting for
|
||
|
+ a place to write to, signal him that
|
||
|
+ now there is this very place */
|
||
|
+ g_cond_signal (priv->cond);
|
||
|
+ }
|
||
|
+
|
||
|
+ n = _g_mem_pipe_poll (mem_pipe, GPD_READ, cancellable, error);
|
||
|
+
|
||
|
+ if (n > 0)
|
||
|
+ {
|
||
|
+ nread = MIN (count, n);
|
||
|
+
|
||
|
+ if (is_buffered)
|
||
|
+ {
|
||
|
+ memcpy (buffer, priv->buffer.data, nread);
|
||
|
+ g_memmove (priv->buffer.data, priv->buffer.data + nread, nread);
|
||
|
+ priv->buffer.dlen -= nread;
|
||
|
+
|
||
|
+ /* There should be room now in the buffer,
|
||
|
+ maybe get more data right now */
|
||
|
+ g_cond_signal (priv->cond);
|
||
|
+ }
|
||
|
+ else
|
||
|
+ priv->buffer.dlen = priv->buffer.size = 0;
|
||
|
+ }
|
||
|
+ else
|
||
|
+ nread = n;
|
||
|
+
|
||
|
+ g_mutex_unlock (priv->lock);
|
||
|
+ g_cancellable_disconnect (cancellable, handler_id);
|
||
|
+
|
||
|
+ return nread;
|
||
|
+}
|
||
|
+
|
||
|
+gssize
|
||
|
+g_mem_pipe_write (GMemPipe *mem_pipe,
|
||
|
+ const void *buffer,
|
||
|
+ gsize count,
|
||
|
+ GCancellable *cancellable,
|
||
|
+ GError **error)
|
||
|
+{
|
||
|
+ GMemPipePrivate *priv;
|
||
|
+ gssize n;
|
||
|
+ gssize nwritten;
|
||
|
+ gulong handler_id;
|
||
|
+
|
||
|
+ g_return_val_if_fail (G_IS_MEM_PIPE (mem_pipe), -1);
|
||
|
+
|
||
|
+ if (count == 0)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ priv = mem_pipe->priv;
|
||
|
+ handler_id = _g_mem_pipe_cancellable_connect (mem_pipe, cancellable);
|
||
|
+
|
||
|
+ g_mutex_lock (priv->lock);
|
||
|
+
|
||
|
+ n = _g_mem_pipe_poll (mem_pipe, GPD_WRITE, cancellable, error);
|
||
|
+
|
||
|
+ if (n > 0)
|
||
|
+ {
|
||
|
+ nwritten = MIN (count, n);
|
||
|
+ memcpy (priv->buffer.data + priv->buffer.dlen, buffer, nwritten);
|
||
|
+ priv->buffer.dlen += nwritten;
|
||
|
+
|
||
|
+ /* data is now available, wake up any sleeping thread */
|
||
|
+ g_cond_signal (priv->cond);
|
||
|
+ }
|
||
|
+ else
|
||
|
+ nwritten = n;
|
||
|
+
|
||
|
+ g_mutex_unlock (priv->lock);
|
||
|
+ g_cancellable_disconnect (cancellable, handler_id);
|
||
|
+
|
||
|
+ return nwritten;
|
||
|
+}
|
||
|
+
|
||
|
+gboolean
|
||
|
+g_mem_pipe_write_all (GMemPipe *mem_pipe,
|
||
|
+ const void *buffer,
|
||
|
+ gsize count,
|
||
|
+ gsize *bytes_written,
|
||
|
+ GCancellable *cancellable,
|
||
|
+ GError **error)
|
||
|
+{
|
||
|
+ gssize n;
|
||
|
+ gsize nwritten;
|
||
|
+ gboolean res;
|
||
|
+
|
||
|
+ g_return_val_if_fail (G_IS_MEM_PIPE (mem_pipe), FALSE);
|
||
|
+
|
||
|
+ nwritten = 0;
|
||
|
+ res = TRUE;
|
||
|
+
|
||
|
+ do
|
||
|
+ {
|
||
|
+ n = g_mem_pipe_write (mem_pipe,
|
||
|
+ buffer + nwritten,
|
||
|
+ count - nwritten,
|
||
|
+ cancellable,
|
||
|
+ error);
|
||
|
+
|
||
|
+ if (n < 0)
|
||
|
+ break;
|
||
|
+
|
||
|
+ nwritten += n;
|
||
|
+
|
||
|
+ }
|
||
|
+ while (nwritten != count);
|
||
|
+
|
||
|
+ if (bytes_written != NULL)
|
||
|
+ *bytes_written = nwritten;
|
||
|
+
|
||
|
+ return nwritten == count;
|
||
|
+}
|
||
|
+
|
||
|
+gboolean
|
||
|
+g_mem_pipe_close_write (GMemPipe *mem_pipe,
|
||
|
+ GCancellable *cancellable,
|
||
|
+ GError **error)
|
||
|
+{
|
||
|
+ GMemPipePrivate *priv;
|
||
|
+
|
||
|
+ g_return_val_if_fail (G_IS_MEM_PIPE (mem_pipe), FALSE);
|
||
|
+
|
||
|
+ priv = mem_pipe->priv;
|
||
|
+ g_mutex_lock (priv->lock);
|
||
|
+ priv->closed |= GPD_WRITE;
|
||
|
+ g_cond_signal (priv->cond);
|
||
|
+ g_mutex_unlock (priv->lock);
|
||
|
+
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+gboolean
|
||
|
+g_mem_pipe_close_read (GMemPipe *mem_pipe,
|
||
|
+ GCancellable *cancellable,
|
||
|
+ GError **error)
|
||
|
+{
|
||
|
+ GMemPipePrivate *priv;
|
||
|
+
|
||
|
+ g_return_val_if_fail (G_IS_MEM_PIPE (mem_pipe), FALSE);
|
||
|
+
|
||
|
+ priv = mem_pipe->priv;
|
||
|
+
|
||
|
+ g_mutex_lock (priv->lock);
|
||
|
+ priv->closed |= GPD_READ;
|
||
|
+ g_cond_signal (priv->cond);
|
||
|
+ g_mutex_unlock (priv->lock);
|
||
|
+
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+GMemPipe *
|
||
|
+g_mem_pipe_new ()
|
||
|
+{
|
||
|
+ GMemPipe *mem_pipe;
|
||
|
+
|
||
|
+ mem_pipe = g_object_new (G_TYPE_MEM_PIPE, NULL);
|
||
|
+
|
||
|
+ return mem_pipe;
|
||
|
+}
|
||
|
+
|
||
|
+GMemPipe *
|
||
|
+g_mem_pipe_buffered_new (gsize buffer_size)
|
||
|
+{
|
||
|
+ GMemPipe *mem_pipe;
|
||
|
+
|
||
|
+ mem_pipe = g_object_new (G_TYPE_MEM_PIPE,
|
||
|
+ "buffer-size", buffer_size,
|
||
|
+ NULL);
|
||
|
+ return mem_pipe;
|
||
|
+}
|
||
|
+
|
||
|
+GInputStream *
|
||
|
+g_mem_pipe_get_input_stream (GMemPipe *mem_pipe)
|
||
|
+{
|
||
|
+ GMemPipePrivate *priv;
|
||
|
+
|
||
|
+ g_return_val_if_fail (G_IS_MEM_PIPE (mem_pipe), FALSE);
|
||
|
+
|
||
|
+ priv = mem_pipe->priv;
|
||
|
+ return g_object_ref (priv->input_stream);
|
||
|
+}
|
||
|
+
|
||
|
+GOutputStream *
|
||
|
+g_mem_pipe_get_output_stream (GMemPipe *mem_pipe)
|
||
|
+{
|
||
|
+ GMemPipePrivate *priv;
|
||
|
+
|
||
|
+ g_return_val_if_fail (G_IS_MEM_PIPE (mem_pipe), FALSE);
|
||
|
+
|
||
|
+ priv = mem_pipe->priv;
|
||
|
+ return g_object_ref (priv->output_stream);
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+/* *********************************************************************** */
|
||
|
+/* streams */
|
||
|
+
|
||
|
+/* ********************************* */
|
||
|
+/* input stream */
|
||
|
+typedef GInputStreamClass GMemPipeInputStreamClass;
|
||
|
+struct _GMemPipeInputStream
|
||
|
+{
|
||
|
+ GInputStream parent_instance;
|
||
|
+ GMemPipe *mem_pipe;
|
||
|
+};
|
||
|
+
|
||
|
+#define G_TYPE_MEM_PIPE_INPUT_STREAM (g_mem_pipe_input_stream_get_type ())
|
||
|
+#define G_MEM_PIPE_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), \
|
||
|
+ G_TYPE_MEM_PIPE_INPUT_STREAM, \
|
||
|
+ GMemPipeInputStream))
|
||
|
+#define G_IS_MEM_PIPE_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), \
|
||
|
+ G_TYPE_MEM_PIPE_INPUT_STREAM))
|
||
|
+
|
||
|
+GType g_mem_pipe_input_stream_get_type (void) G_GNUC_CONST;
|
||
|
+
|
||
|
+G_DEFINE_TYPE (GMemPipeInputStream,
|
||
|
+ g_mem_pipe_input_stream,
|
||
|
+ G_TYPE_INPUT_STREAM)
|
||
|
+
|
||
|
+static GInputStream *
|
||
|
+g_mem_pipe_input_stream_new (GMemPipe *mem_pipe)
|
||
|
+{
|
||
|
+ GMemPipeInputStream *istream;
|
||
|
+ istream = g_object_new (G_TYPE_MEM_PIPE_INPUT_STREAM, NULL);
|
||
|
+
|
||
|
+ istream->mem_pipe = g_object_ref (mem_pipe);
|
||
|
+ return G_INPUT_STREAM (istream);
|
||
|
+}
|
||
|
+
|
||
|
+static gssize
|
||
|
+g_mem_pipe_input_stream_read (GInputStream *stream,
|
||
|
+ void *buffer,
|
||
|
+ gsize length,
|
||
|
+ GCancellable *cancellable,
|
||
|
+ GError **error)
|
||
|
+{
|
||
|
+ GMemPipeInputStream *istream = (GMemPipeInputStream *) stream;
|
||
|
+
|
||
|
+ return g_mem_pipe_read (istream->mem_pipe,
|
||
|
+ buffer,
|
||
|
+ length,
|
||
|
+ cancellable,
|
||
|
+ error);
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean
|
||
|
+g_mem_pipe_input_stream_close (GInputStream *stream,
|
||
|
+ GCancellable *cancellable,
|
||
|
+ GError **error)
|
||
|
+{
|
||
|
+ GMemPipeInputStream *istream = (GMemPipeInputStream *) stream;
|
||
|
+
|
||
|
+ return g_mem_pipe_close_read (istream->mem_pipe,
|
||
|
+ cancellable,
|
||
|
+ error);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+g_mem_pipe_input_stream_init (GMemPipeInputStream *self)
|
||
|
+{
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+g_mem_pipe_input_stream_dispose (GObject *object)
|
||
|
+{
|
||
|
+ GMemPipeInputStream *istream;
|
||
|
+
|
||
|
+ istream = G_MEM_PIPE_INPUT_STREAM (object);
|
||
|
+
|
||
|
+ if (istream->mem_pipe != NULL)
|
||
|
+ {
|
||
|
+ g_object_unref (istream->mem_pipe);
|
||
|
+ istream->mem_pipe = NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ G_OBJECT_CLASS (g_mem_pipe_input_stream_parent_class)->dispose (object);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+g_mem_pipe_input_stream_class_init (GMemPipeInputStreamClass *klass)
|
||
|
+{
|
||
|
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||
|
+ GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
|
||
|
+
|
||
|
+ gobject_class->dispose = g_mem_pipe_input_stream_dispose;
|
||
|
+ stream_class->read_fn = g_mem_pipe_input_stream_read;
|
||
|
+ stream_class->close_fn = g_mem_pipe_input_stream_close;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+/* ********************************* */
|
||
|
+/* output stream */
|
||
|
+typedef GOutputStreamClass GMemPipeOutputStreamClass;
|
||
|
+struct _GMemPipeOutputStream
|
||
|
+{
|
||
|
+ GOutputStream parent_instance;
|
||
|
+ GMemPipe *mem_pipe;
|
||
|
+};
|
||
|
+
|
||
|
+#define G_TYPE_MEM_PIPE_OUTPUT_STREAM (g_mem_pipe_output_stream_get_type ())
|
||
|
+#define G_MEM_PIPE_OUTPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), \
|
||
|
+ G_TYPE_MEM_PIPE_OUTPUT_STREAM, \
|
||
|
+ GMemPipeOutputStream))
|
||
|
+#define G_IS_MEM_PIPE_OUTPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), \
|
||
|
+ G_TYPE_MEM_PIPE_OUTPUT_STREAM))
|
||
|
+
|
||
|
+GType g_mem_pipe_output_stream_get_type (void) G_GNUC_CONST;
|
||
|
+
|
||
|
+G_DEFINE_TYPE (GMemPipeOutputStream,
|
||
|
+ g_mem_pipe_output_stream,
|
||
|
+ G_TYPE_OUTPUT_STREAM)
|
||
|
+
|
||
|
+static GOutputStream *
|
||
|
+g_mem_pipe_output_stream_new (GMemPipe *mem_pipe)
|
||
|
+{
|
||
|
+ GMemPipeOutputStream *ostream;
|
||
|
+ ostream = g_object_new (G_TYPE_MEM_PIPE_OUTPUT_STREAM, NULL);
|
||
|
+
|
||
|
+ ostream->mem_pipe = g_object_ref (mem_pipe);
|
||
|
+ return G_OUTPUT_STREAM (ostream);
|
||
|
+}
|
||
|
+
|
||
|
+static gssize
|
||
|
+g_mem_pipe_output_stream_write (GOutputStream *stream,
|
||
|
+ const void *buffer,
|
||
|
+ gsize count,
|
||
|
+ GCancellable *cancellable,
|
||
|
+ GError **error)
|
||
|
+{
|
||
|
+ GMemPipeOutputStream *ostream = (GMemPipeOutputStream *) stream;
|
||
|
+
|
||
|
+ return g_mem_pipe_write (ostream->mem_pipe,
|
||
|
+ buffer,
|
||
|
+ count,
|
||
|
+ cancellable,
|
||
|
+ error);
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean
|
||
|
+g_mem_pipe_output_stream_close (GOutputStream *stream,
|
||
|
+ GCancellable *cancellable,
|
||
|
+ GError **error)
|
||
|
+{
|
||
|
+ GMemPipeOutputStream *ostream = (GMemPipeOutputStream *) stream;
|
||
|
+
|
||
|
+ g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (stream), FALSE);
|
||
|
+
|
||
|
+ return g_mem_pipe_close_write (ostream->mem_pipe,
|
||
|
+ cancellable,
|
||
|
+ error);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+g_mem_pipe_output_stream_init (GMemPipeOutputStream *self)
|
||
|
+{
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+g_mem_pipe_output_stream_dispose (GObject *object)
|
||
|
+{
|
||
|
+ GMemPipeOutputStream *ostream;
|
||
|
+
|
||
|
+ ostream = G_MEM_PIPE_OUTPUT_STREAM (object);
|
||
|
+
|
||
|
+ if (ostream->mem_pipe != NULL)
|
||
|
+ {
|
||
|
+ g_object_unref (ostream->mem_pipe);
|
||
|
+ ostream->mem_pipe = NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ G_OBJECT_CLASS (g_mem_pipe_output_stream_parent_class)->dispose (object);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+g_mem_pipe_output_stream_class_init (GMemPipeOutputStreamClass *klass)
|
||
|
+{
|
||
|
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||
|
+ GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);
|
||
|
+
|
||
|
+ gobject_class->dispose = g_mem_pipe_output_stream_dispose;
|
||
|
+ stream_class->write_fn = g_mem_pipe_output_stream_write;
|
||
|
+ stream_class->close_fn = g_mem_pipe_output_stream_close;
|
||
|
+}
|
||
|
diff --git a/daemon/gmempipe.h b/daemon/gmempipe.h
|
||
|
new file mode 100644
|
||
|
index 0000000..c9b1cd3
|
||
|
--- /dev/null
|
||
|
+++ b/daemon/gmempipe.h
|
||
|
@@ -0,0 +1,86 @@
|
||
|
+/* GIO - GLib Input, Output and Streaming Library
|
||
|
+ *
|
||
|
+ * Copyright (C) Christian Kellner <gicmo@gnome.org>
|
||
|
+ *
|
||
|
+ * This library is free software; you can redistribute it and/or
|
||
|
+ * modify it under the terms of the GNU Lesser General Public
|
||
|
+ * License as published by the Free Software Foundation; either
|
||
|
+ * version 2 of the License, or (at your option) any later version.
|
||
|
+ *
|
||
|
+ * This library is distributed in the hope that it will be useful,
|
||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
+ * Lesser General Public License for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU Lesser General
|
||
|
+ * Public License along with this library; if not, write to the
|
||
|
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||
|
+ * Boston, MA 02111-1307, USA.
|
||
|
+ *
|
||
|
+ * Author: Christian Kellner <gicmo@gnome.org>
|
||
|
+ */
|
||
|
+
|
||
|
+#ifndef __G_MEM_PIPE_H__
|
||
|
+#define __G_MEM_PIPE_H__
|
||
|
+
|
||
|
+#include <glib-object.h>
|
||
|
+#include <gio/gio.h>
|
||
|
+
|
||
|
+G_BEGIN_DECLS
|
||
|
+
|
||
|
+#define G_TYPE_MEM_PIPE (g_mem_pipe_get_type ())
|
||
|
+#define G_MEM_PIPE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_MEM_PIPE, GMemPipe))
|
||
|
+#define G_MEM_PIPE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_MEM_PIPE, GMemPipeClass))
|
||
|
+#define G_IS_MEM_PIPE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_MEM_PIPE))
|
||
|
+#define G_IS_MEM_PIPE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TPE_MEM_PIPE))
|
||
|
+#define G_MEM_PIPE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_MEM_PIPE, GMemPipeClass))
|
||
|
+
|
||
|
+typedef struct _GMemPipe GMemPipe;
|
||
|
+typedef struct _GMemPipePrivate GMemPipePrivate;
|
||
|
+typedef struct _GMemPipeClass GMemPipeClass;
|
||
|
+
|
||
|
+struct _GMemPipe
|
||
|
+{
|
||
|
+ GObject parent_instance;
|
||
|
+
|
||
|
+ GMemPipePrivate *priv;
|
||
|
+};
|
||
|
+
|
||
|
+struct _GMemPipeClass
|
||
|
+{
|
||
|
+ GObjectClass parent_class;
|
||
|
+
|
||
|
+};
|
||
|
+
|
||
|
+GType g_mem_pipe_get_type (void) G_GNUC_CONST;
|
||
|
+GMemPipe * g_mem_pipe_new (void);
|
||
|
+GMemPipe * g_mem_pipe_buffered_new (gsize buffer_size);
|
||
|
+gssize g_mem_pipe_write (GMemPipe *mem_pipe,
|
||
|
+ const void *buffer,
|
||
|
+ gsize count,
|
||
|
+ GCancellable *cancellable,
|
||
|
+ GError **error);
|
||
|
+gboolean g_mem_pipe_write_all (GMemPipe *mem_pipe,
|
||
|
+ const void *buffer,
|
||
|
+ gsize count,
|
||
|
+ gsize *bytes_written,
|
||
|
+ GCancellable *cancellable,
|
||
|
+ GError **error);
|
||
|
+gssize g_mem_pipe_read (GMemPipe *mem_pipe,
|
||
|
+ void *buffer,
|
||
|
+ gsize count,
|
||
|
+ GCancellable *cancellable,
|
||
|
+ GError **error);
|
||
|
+gboolean g_mem_pipe_close_write (GMemPipe *mem_pipe,
|
||
|
+ GCancellable *cancellable,
|
||
|
+ GError **error);
|
||
|
+gboolean g_mem_pipe_close_read (GMemPipe *mem_pipe,
|
||
|
+ GCancellable *cancellable,
|
||
|
+ GError **error);
|
||
|
+GInputStream *g_mem_pipe_get_input_stream (GMemPipe *mem_pipe);
|
||
|
+GOutputStream *g_mem_pipe_get_output_stream (GMemPipe *mem_pipe);
|
||
|
+
|
||
|
+
|
||
|
+G_END_DECLS
|
||
|
+
|
||
|
+#endif /* __G_MEM_PIPE_H__ */
|
||
|
diff --git a/daemon/gvfsbackenddav.c b/daemon/gvfsbackenddav.c
|
||
|
index 95dc428..0862249 100644
|
||
|
--- a/daemon/gvfsbackenddav.c
|
||
|
+++ b/daemon/gvfsbackenddav.c
|
||
|
@@ -2313,6 +2313,47 @@ try_unmount (GVfsBackend *backend,
|
||
|
_exit (0);
|
||
|
}
|
||
|
|
||
|
+
|
||
|
+/* *** overwrite http backend method *** */
|
||
|
+static void
|
||
|
+do_open_for_read (GVfsBackend *backend,
|
||
|
+ GVfsJobOpenForRead *job,
|
||
|
+ const char *filename)
|
||
|
+{
|
||
|
+ SoupURI *uri;
|
||
|
+ GFileType file_type;
|
||
|
+ gboolean res;
|
||
|
+ guint num_children;
|
||
|
+ GError *error;
|
||
|
+
|
||
|
+ error = NULL;
|
||
|
+
|
||
|
+ uri = http_backend_uri_for_filename (backend, filename, FALSE);
|
||
|
+ res = stat_location (backend, uri, &file_type, &num_children, &error);
|
||
|
+ soup_uri_free (uri);
|
||
|
+
|
||
|
+ if (res == FALSE)
|
||
|
+ {
|
||
|
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
|
||
|
+ g_error_free (error);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (file_type == G_FILE_TYPE_DIRECTORY)
|
||
|
+ {
|
||
|
+ g_vfs_job_failed (G_VFS_JOB (job),
|
||
|
+ G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
|
||
|
+ _("Directory not empty"));
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* the real work happens in the parent class */
|
||
|
+ G_VFS_BACKEND_CLASS (g_vfs_backend_dav_parent_class)->open_for_read (backend,
|
||
|
+ job,
|
||
|
+ filename);
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
/* ************************************************************************* */
|
||
|
/* */
|
||
|
static void
|
||
|
@@ -2326,6 +2367,8 @@ g_vfs_backend_dav_class_init (GVfsBackendDavClass *klass)
|
||
|
|
||
|
backend_class = G_VFS_BACKEND_CLASS (klass);
|
||
|
|
||
|
+ backend_class->open_for_read = do_open_for_read;
|
||
|
+
|
||
|
backend_class->try_mount = NULL;
|
||
|
backend_class->mount = do_mount;
|
||
|
backend_class->try_query_info = NULL;
|
||
|
diff --git a/daemon/gvfsbackendhttp.c b/daemon/gvfsbackendhttp.c
|
||
|
index 976e0ed..8534d83 100644
|
||
|
--- a/daemon/gvfsbackendhttp.c
|
||
|
+++ b/daemon/gvfsbackendhttp.c
|
||
|
@@ -239,7 +239,6 @@ http_error_code_from_status (guint status)
|
||
|
return G_IO_ERROR_FAILED;
|
||
|
}
|
||
|
|
||
|
-
|
||
|
static void
|
||
|
g_vfs_job_failed_from_http_status (GVfsJob *job, guint status_code, const char *message)
|
||
|
{
|
||
|
@@ -262,6 +261,16 @@ g_vfs_job_failed_from_http_status (GVfsJob *job, guint status_code, const char *
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+static void
|
||
|
+g_vfs_job_failed_from_soup_error (GVfsJob *job, GError *error)
|
||
|
+{
|
||
|
+ if (error->domain == SOUP_HTTP_ERROR)
|
||
|
+ g_vfs_job_failed_from_http_status (job, error->code, error->message);
|
||
|
+ else
|
||
|
+ g_vfs_job_failed_literal (job, error->domain, error->code, error->message);
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
guint
|
||
|
http_backend_send_message (GVfsBackend *backend,
|
||
|
SoupMessage *msg)
|
||
|
@@ -335,53 +344,17 @@ try_mount (GVfsBackend *backend,
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
-/* *** open_read () *** */
|
||
|
-static void
|
||
|
-open_for_read_ready (GObject *source_object,
|
||
|
- GAsyncResult *result,
|
||
|
- gpointer user_data)
|
||
|
-{
|
||
|
- GInputStream *stream;
|
||
|
- GVfsJob *job;
|
||
|
- gboolean res;
|
||
|
- gboolean can_seek;
|
||
|
- GError *error;
|
||
|
-
|
||
|
- stream = G_INPUT_STREAM (source_object);
|
||
|
- error = NULL;
|
||
|
- job = G_VFS_JOB (user_data);
|
||
|
-
|
||
|
- res = soup_input_stream_send_finish (stream,
|
||
|
- result,
|
||
|
- &error);
|
||
|
- if (res == FALSE)
|
||
|
- {
|
||
|
- g_vfs_job_failed_literal (G_VFS_JOB (job),
|
||
|
- error->domain,
|
||
|
- error->code,
|
||
|
- error->message);
|
||
|
-
|
||
|
- g_error_free (error);
|
||
|
- g_object_unref (stream);
|
||
|
- return;
|
||
|
- }
|
||
|
-
|
||
|
- can_seek = G_IS_SEEKABLE (stream) && g_seekable_can_seek (G_SEEKABLE (stream));
|
||
|
-
|
||
|
- g_vfs_job_open_for_read_set_can_seek (G_VFS_JOB_OPEN_FOR_READ (job), can_seek);
|
||
|
- g_vfs_job_open_for_read_set_handle (G_VFS_JOB_OPEN_FOR_READ (job), stream);
|
||
|
- g_vfs_job_succeeded (job);
|
||
|
-}
|
||
|
-
|
||
|
-static gboolean
|
||
|
-try_open_for_read (GVfsBackend *backend,
|
||
|
- GVfsJobOpenForRead *job,
|
||
|
- const char *filename)
|
||
|
+static void
|
||
|
+do_open_for_read (GVfsBackend *backend,
|
||
|
+ GVfsJobOpenForRead *job,
|
||
|
+ const char *filename)
|
||
|
{
|
||
|
GVfsBackendHttp *op_backend;
|
||
|
GInputStream *stream;
|
||
|
SoupMessage *msg;
|
||
|
SoupURI *uri;
|
||
|
+ GError *error;
|
||
|
+ gboolean res;
|
||
|
|
||
|
op_backend = G_VFS_BACKEND_HTTP (backend);
|
||
|
uri = http_backend_uri_for_filename (backend, filename, FALSE);
|
||
|
@@ -390,125 +363,119 @@ try_open_for_read (GVfsBackend *backend,
|
||
|
|
||
|
soup_message_body_set_accumulate (msg->response_body, FALSE);
|
||
|
|
||
|
- stream = soup_input_stream_new (op_backend->session_async, msg);
|
||
|
+ stream = soup_input_stream_new (op_backend->session, msg);
|
||
|
g_object_unref (msg);
|
||
|
|
||
|
- soup_input_stream_send_async (stream,
|
||
|
- G_PRIORITY_DEFAULT,
|
||
|
- G_VFS_JOB (job)->cancellable,
|
||
|
- open_for_read_ready,
|
||
|
- job);
|
||
|
- return TRUE;
|
||
|
+ error = NULL;
|
||
|
+ res = soup_input_stream_send (stream,
|
||
|
+ G_VFS_JOB (job)->cancellable,
|
||
|
+ &error);
|
||
|
+
|
||
|
+ if (res == FALSE)
|
||
|
+ {
|
||
|
+ g_vfs_job_failed_from_soup_error (G_VFS_JOB (job), error);
|
||
|
+ g_error_free (error);
|
||
|
+ g_object_unref (stream);
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ gboolean can_seek;
|
||
|
+ can_seek = G_IS_SEEKABLE (stream) && g_seekable_can_seek (G_SEEKABLE (stream));
|
||
|
+
|
||
|
+ g_vfs_job_open_for_read_set_can_seek (G_VFS_JOB_OPEN_FOR_READ (job), can_seek);
|
||
|
+ g_vfs_job_open_for_read_set_handle (G_VFS_JOB_OPEN_FOR_READ (job), stream);
|
||
|
+
|
||
|
+ g_vfs_job_succeeded (G_VFS_JOB (job));
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
-/* *** read () *** */
|
||
|
static void
|
||
|
-read_ready (GObject *source_object,
|
||
|
- GAsyncResult *result,
|
||
|
- gpointer user_data)
|
||
|
+do_read (GVfsBackend * backend,
|
||
|
+ GVfsJobRead * job,
|
||
|
+ GVfsBackendHandle handle,
|
||
|
+ char * buffer,
|
||
|
+ gsize bytes_requested)
|
||
|
{
|
||
|
GInputStream *stream;
|
||
|
- GVfsJob *job;
|
||
|
GError *error;
|
||
|
- gssize nread;
|
||
|
-
|
||
|
- stream = G_INPUT_STREAM (source_object);
|
||
|
- error = NULL;
|
||
|
- job = G_VFS_JOB (user_data);
|
||
|
-
|
||
|
- nread = g_input_stream_read_finish (stream, result, &error);
|
||
|
-
|
||
|
- if (nread < 0)
|
||
|
- {
|
||
|
- g_vfs_job_failed_literal (G_VFS_JOB (job),
|
||
|
- error->domain,
|
||
|
- error->code,
|
||
|
- error->message);
|
||
|
+ gssize n_bytes;
|
||
|
|
||
|
- g_error_free (error);
|
||
|
- return;
|
||
|
- }
|
||
|
+ stream = G_INPUT_STREAM (handle);
|
||
|
|
||
|
- g_vfs_job_read_set_size (G_VFS_JOB_READ (job), nread);
|
||
|
- g_vfs_job_succeeded (job);
|
||
|
+ error = NULL;
|
||
|
+ n_bytes = g_input_stream_read (stream,
|
||
|
+ buffer,
|
||
|
+ bytes_requested,
|
||
|
+ G_VFS_JOB (job)->cancellable,
|
||
|
+ &error);
|
||
|
|
||
|
+ if (n_bytes >= 0)
|
||
|
+ {
|
||
|
+ g_vfs_job_read_set_size (job, n_bytes);
|
||
|
+ g_vfs_job_succeeded (G_VFS_JOB (job));
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ g_vfs_job_failed_from_soup_error (G_VFS_JOB (job), error);
|
||
|
+ g_error_free (error);
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
-static gboolean
|
||
|
-try_read (GVfsBackend *backend,
|
||
|
- GVfsJobRead *job,
|
||
|
- GVfsBackendHandle handle,
|
||
|
- char *buffer,
|
||
|
- gsize bytes_requested)
|
||
|
-{
|
||
|
- GInputStream *stream;
|
||
|
|
||
|
- stream = G_INPUT_STREAM (handle);
|
||
|
-
|
||
|
- g_input_stream_read_async (stream,
|
||
|
- buffer,
|
||
|
- bytes_requested,
|
||
|
- G_PRIORITY_DEFAULT,
|
||
|
- G_VFS_JOB (job)->cancellable,
|
||
|
- read_ready,
|
||
|
- job);
|
||
|
- return TRUE;
|
||
|
-}
|
||
|
-
|
||
|
-static gboolean
|
||
|
-try_seek_on_read (GVfsBackend *backend,
|
||
|
- GVfsJobSeekRead *job,
|
||
|
- GVfsBackendHandle handle,
|
||
|
- goffset offset,
|
||
|
- GSeekType type)
|
||
|
+static void
|
||
|
+do_seek_on_read (GVfsBackend *backend,
|
||
|
+ GVfsJobSeekRead *job,
|
||
|
+ GVfsBackendHandle handle,
|
||
|
+ goffset offset,
|
||
|
+ GSeekType type)
|
||
|
{
|
||
|
- GInputStream *stream;
|
||
|
- GError *error = NULL;
|
||
|
+ GInputStream *stream;
|
||
|
+ GError *error = NULL;
|
||
|
+ gboolean res;
|
||
|
|
||
|
stream = G_INPUT_STREAM (handle);
|
||
|
|
||
|
- if (!g_seekable_seek (G_SEEKABLE (stream), offset, type,
|
||
|
- G_VFS_JOB (job)->cancellable, &error))
|
||
|
+
|
||
|
+ res = g_seekable_seek (G_SEEKABLE (stream),
|
||
|
+ offset,
|
||
|
+ type,
|
||
|
+ G_VFS_JOB (job)->cancellable,
|
||
|
+ &error);
|
||
|
+
|
||
|
+ if (res == FALSE)
|
||
|
{
|
||
|
- g_vfs_job_failed_literal (G_VFS_JOB (job),
|
||
|
- error->domain,
|
||
|
- error->code,
|
||
|
- error->message);
|
||
|
+ g_vfs_job_failed_from_soup_error (G_VFS_JOB (job), error);
|
||
|
g_error_free (error);
|
||
|
- return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_vfs_job_seek_read_set_offset (job, g_seekable_tell (G_SEEKABLE (stream)));
|
||
|
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||
|
}
|
||
|
-
|
||
|
- return TRUE;
|
||
|
}
|
||
|
|
||
|
/* *** read_close () *** */
|
||
|
static void
|
||
|
-close_read_ready (GObject *source_object,
|
||
|
- GAsyncResult *result,
|
||
|
- gpointer user_data)
|
||
|
+do_close_read (GVfsBackend *backend,
|
||
|
+ GVfsJobCloseRead *read_job,
|
||
|
+ GVfsBackendHandle handle)
|
||
|
{
|
||
|
GInputStream *stream;
|
||
|
GVfsJob *job;
|
||
|
GError *error;
|
||
|
gboolean res;
|
||
|
|
||
|
- job = G_VFS_JOB (user_data);
|
||
|
- stream = G_INPUT_STREAM (source_object);
|
||
|
- res = g_input_stream_close_finish (stream,
|
||
|
- result,
|
||
|
- &error);
|
||
|
+ error = NULL;
|
||
|
+ job = G_VFS_JOB (read_job);
|
||
|
+ stream = G_INPUT_STREAM (handle);
|
||
|
+
|
||
|
+
|
||
|
+ res = g_input_stream_close (stream,
|
||
|
+ job->cancellable,
|
||
|
+ &error);
|
||
|
if (res == FALSE)
|
||
|
{
|
||
|
- g_vfs_job_failed_literal (G_VFS_JOB (job),
|
||
|
- error->domain,
|
||
|
- error->code,
|
||
|
- error->message);
|
||
|
-
|
||
|
+ g_vfs_job_failed_from_soup_error (G_VFS_JOB (job), error);
|
||
|
g_error_free (error);
|
||
|
}
|
||
|
else
|
||
|
@@ -517,24 +484,6 @@ close_read_ready (GObject *source_object,
|
||
|
g_object_unref (stream);
|
||
|
}
|
||
|
|
||
|
-static gboolean
|
||
|
-try_close_read (GVfsBackend *backend,
|
||
|
- GVfsJobCloseRead *job,
|
||
|
- GVfsBackendHandle handle)
|
||
|
-{
|
||
|
- GInputStream *stream;
|
||
|
-
|
||
|
- stream = G_INPUT_STREAM (handle);
|
||
|
-
|
||
|
- g_input_stream_close_async (stream,
|
||
|
- G_PRIORITY_DEFAULT,
|
||
|
- G_VFS_JOB (job)->cancellable,
|
||
|
- close_read_ready,
|
||
|
- job);
|
||
|
- return TRUE;
|
||
|
-}
|
||
|
-
|
||
|
-
|
||
|
/* *** query_info () *** */
|
||
|
|
||
|
static void
|
||
|
@@ -688,10 +637,12 @@ g_vfs_backend_http_class_init (GVfsBackendHttpClass *klass)
|
||
|
backend_class = G_VFS_BACKEND_CLASS (klass);
|
||
|
|
||
|
backend_class->try_mount = try_mount;
|
||
|
- backend_class->try_open_for_read = try_open_for_read;
|
||
|
- backend_class->try_read = try_read;
|
||
|
- backend_class->try_seek_on_read = try_seek_on_read;
|
||
|
- backend_class->try_close_read = try_close_read;
|
||
|
+
|
||
|
+ backend_class->open_for_read = do_open_for_read;
|
||
|
+ backend_class->close_read = do_close_read;
|
||
|
+ backend_class->read = do_read;
|
||
|
+ backend_class->seek_on_read = do_seek_on_read;
|
||
|
+
|
||
|
backend_class->try_query_info = try_query_info;
|
||
|
backend_class->try_query_info_on_read = try_query_info_on_read;
|
||
|
}
|
||
|
diff --git a/daemon/soup-input-stream.c b/daemon/soup-input-stream.c
|
||
|
index e1928af..10af4dd 100644
|
||
|
--- a/daemon/soup-input-stream.c
|
||
|
+++ b/daemon/soup-input-stream.c
|
||
|
@@ -18,7 +18,7 @@
|
||
|
* Boston, MA 02111-1307, USA.
|
||
|
*/
|
||
|
|
||
|
-#include <config.h>
|
||
|
+//#include <config.h>
|
||
|
|
||
|
#include <string.h>
|
||
|
|
||
|
@@ -28,6 +28,7 @@
|
||
|
#include <libsoup/soup.h>
|
||
|
|
||
|
#include "soup-input-stream.h"
|
||
|
+#include "gmempipe.h"
|
||
|
|
||
|
static void soup_input_stream_seekable_iface_init (GSeekableIface *seekable_iface);
|
||
|
|
||
|
@@ -37,29 +38,23 @@ G_DEFINE_TYPE_WITH_CODE (SoupInputStream, soup_input_stream, G_TYPE_INPUT_STREAM
|
||
|
|
||
|
typedef void (*SoupInputStreamCallback) (GInputStream *);
|
||
|
|
||
|
-typedef struct {
|
||
|
+struct SoupInputStreamPrivate {
|
||
|
SoupSession *session;
|
||
|
- GMainContext *async_context;
|
||
|
SoupMessage *msg;
|
||
|
+
|
||
|
gboolean got_headers, finished;
|
||
|
goffset offset;
|
||
|
|
||
|
- GCancellable *cancellable;
|
||
|
- GSource *cancel_watch;
|
||
|
- SoupInputStreamCallback got_headers_cb;
|
||
|
- SoupInputStreamCallback got_chunk_cb;
|
||
|
- SoupInputStreamCallback finished_cb;
|
||
|
- SoupInputStreamCallback cancelled_cb;
|
||
|
+ GMutex *lock;
|
||
|
+ GCond *cond;
|
||
|
+
|
||
|
+ GMemPipe *mem_pipe;
|
||
|
|
||
|
- guchar *leftover_buffer;
|
||
|
- gsize leftover_bufsize, leftover_offset;
|
||
|
+ GInputStream *in;
|
||
|
+ GOutputStream *out;
|
||
|
|
||
|
- guchar *caller_buffer;
|
||
|
- gsize caller_bufsize, caller_nread;
|
||
|
- GAsyncReadyCallback outstanding_callback;
|
||
|
- GSimpleAsyncResult *result;
|
||
|
+};
|
||
|
|
||
|
-} SoupInputStreamPrivate;
|
||
|
#define SOUP_INPUT_STREAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_INPUT_STREAM, SoupInputStreamPrivate))
|
||
|
|
||
|
|
||
|
@@ -71,24 +66,6 @@ static gssize soup_input_stream_read (GInputStream *stream,
|
||
|
static gboolean soup_input_stream_close (GInputStream *stream,
|
||
|
GCancellable *cancellable,
|
||
|
GError **error);
|
||
|
-static void soup_input_stream_read_async (GInputStream *stream,
|
||
|
- void *buffer,
|
||
|
- gsize count,
|
||
|
- int io_priority,
|
||
|
- GCancellable *cancellable,
|
||
|
- GAsyncReadyCallback callback,
|
||
|
- gpointer data);
|
||
|
-static gssize soup_input_stream_read_finish (GInputStream *stream,
|
||
|
- GAsyncResult *result,
|
||
|
- GError **error);
|
||
|
-static void soup_input_stream_close_async (GInputStream *stream,
|
||
|
- int io_priority,
|
||
|
- GCancellable *cancellable,
|
||
|
- GAsyncReadyCallback callback,
|
||
|
- gpointer data);
|
||
|
-static gboolean soup_input_stream_close_finish (GInputStream *stream,
|
||
|
- GAsyncResult *result,
|
||
|
- GError **error);
|
||
|
|
||
|
static goffset soup_input_stream_tell (GSeekable *seekable);
|
||
|
|
||
|
@@ -115,13 +92,25 @@ soup_input_stream_finalize (GObject *object)
|
||
|
SoupInputStream *stream = SOUP_INPUT_STREAM (object);
|
||
|
SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
|
||
|
|
||
|
- g_object_unref (priv->session);
|
||
|
+ g_print ("Finalize\n");
|
||
|
|
||
|
- g_signal_handlers_disconnect_by_func (priv->msg, G_CALLBACK (soup_input_stream_got_headers), stream);
|
||
|
- g_signal_handlers_disconnect_by_func (priv->msg, G_CALLBACK (soup_input_stream_got_chunk), stream);
|
||
|
- g_signal_handlers_disconnect_by_func (priv->msg, G_CALLBACK (soup_input_stream_finished), stream);
|
||
|
- g_object_unref (priv->msg);
|
||
|
- g_free (priv->leftover_buffer);
|
||
|
+ if (priv->session)
|
||
|
+ g_object_unref (priv->session);
|
||
|
+
|
||
|
+ if (priv->msg)
|
||
|
+ g_object_unref (priv->msg);
|
||
|
+
|
||
|
+ if (priv->mem_pipe)
|
||
|
+ {
|
||
|
+ g_object_unref (priv->mem_pipe);
|
||
|
+ g_object_unref (priv->in);
|
||
|
+ g_object_unref (priv->out);
|
||
|
+ }
|
||
|
+
|
||
|
+ g_mutex_free (priv->lock);
|
||
|
+ g_cond_free (priv->cond);
|
||
|
+
|
||
|
+ g_print ("Done!\n");
|
||
|
|
||
|
if (G_OBJECT_CLASS (soup_input_stream_parent_class)->finalize)
|
||
|
(*G_OBJECT_CLASS (soup_input_stream_parent_class)->finalize) (object);
|
||
|
@@ -136,41 +125,77 @@ soup_input_stream_class_init (SoupInputStreamClass *klass)
|
||
|
g_type_class_add_private (klass, sizeof (SoupInputStreamPrivate));
|
||
|
|
||
|
gobject_class->finalize = soup_input_stream_finalize;
|
||
|
-
|
||
|
- stream_class->read_fn = soup_input_stream_read;
|
||
|
+ stream_class->read_fn = soup_input_stream_read;
|
||
|
stream_class->close_fn = soup_input_stream_close;
|
||
|
- stream_class->read_async = soup_input_stream_read_async;
|
||
|
- stream_class->read_finish = soup_input_stream_read_finish;
|
||
|
- stream_class->close_async = soup_input_stream_close_async;
|
||
|
- stream_class->close_finish = soup_input_stream_close_finish;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
soup_input_stream_seekable_iface_init (GSeekableIface *seekable_iface)
|
||
|
{
|
||
|
- seekable_iface->tell = soup_input_stream_tell;
|
||
|
- seekable_iface->can_seek = soup_input_stream_can_seek;
|
||
|
- seekable_iface->seek = soup_input_stream_seek;
|
||
|
+ seekable_iface->tell = soup_input_stream_tell;
|
||
|
+ seekable_iface->can_seek = soup_input_stream_can_seek;
|
||
|
+ seekable_iface->seek = soup_input_stream_seek;
|
||
|
seekable_iface->can_truncate = soup_input_stream_can_truncate;
|
||
|
- seekable_iface->truncate_fn = soup_input_stream_truncate;
|
||
|
+ seekable_iface->truncate_fn = soup_input_stream_truncate;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
soup_input_stream_init (SoupInputStream *stream)
|
||
|
{
|
||
|
- ;
|
||
|
+ SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
|
||
|
+ stream->priv = priv;
|
||
|
+
|
||
|
+ priv->lock = g_mutex_new ();
|
||
|
+ priv->cond = g_cond_new ();
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
-soup_input_stream_queue_message (SoupInputStream *stream)
|
||
|
+_soup_input_stream_queue_msg_and_wait (SoupInputStream *stream)
|
||
|
{
|
||
|
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
|
||
|
+ SoupInputStreamPrivate *priv = stream->priv;
|
||
|
+
|
||
|
+ g_mutex_lock (priv->lock);
|
||
|
+
|
||
|
+ if (priv->mem_pipe)
|
||
|
+ {
|
||
|
+ g_object_unref (priv->mem_pipe);
|
||
|
+ g_object_unref (priv->in);
|
||
|
+ g_object_unref (priv->out);
|
||
|
+ }
|
||
|
+
|
||
|
+ priv->mem_pipe = g_mem_pipe_new ();
|
||
|
+ priv->in = g_mem_pipe_get_input_stream (priv->mem_pipe);
|
||
|
+ priv->out = g_mem_pipe_get_output_stream (priv->mem_pipe);
|
||
|
|
||
|
priv->got_headers = priv->finished = FALSE;
|
||
|
|
||
|
/* Add an extra ref since soup_session_queue_message steals one */
|
||
|
g_object_ref (priv->msg);
|
||
|
soup_session_queue_message (priv->session, priv->msg, NULL, NULL);
|
||
|
+
|
||
|
+ /* wait until we got the headers (or fail?) */
|
||
|
+ while (!priv->got_headers && !priv->finished)
|
||
|
+ g_cond_wait (priv->cond, priv->lock);
|
||
|
+
|
||
|
+ g_mutex_unlock (priv->lock);
|
||
|
+}
|
||
|
+
|
||
|
+extern void soup_message_io_cleanup (SoupMessage *msg);
|
||
|
+
|
||
|
+static void
|
||
|
+_soup_input_stream_cancel_msg_and_wait (SoupInputStream *stream)
|
||
|
+{
|
||
|
+ SoupInputStreamPrivate *priv = stream->priv;
|
||
|
+
|
||
|
+ g_mutex_lock (priv->lock);
|
||
|
+ soup_session_cancel_message (priv->session, priv->msg, SOUP_STATUS_CANCELLED);
|
||
|
+ soup_message_io_cleanup (priv->msg);
|
||
|
+
|
||
|
+ /* FIXME: is this at all necessary? */
|
||
|
+ while (!priv->got_headers && !priv->finished)
|
||
|
+ g_cond_wait (priv->cond, priv->lock);
|
||
|
+
|
||
|
+ g_mutex_unlock (priv->lock);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -181,21 +206,8 @@ soup_input_stream_queue_message (SoupInputStream *stream)
|
||
|
* Prepares to send @msg over @session, and returns a #GInputStream
|
||
|
* that can be used to read the response.
|
||
|
*
|
||
|
- * @msg may not be sent until the first read call; if you need to look
|
||
|
- * at the status code or response headers before reading the body, you
|
||
|
- * can use soup_input_stream_send() or soup_input_stream_send_async()
|
||
|
- * to force the message to be sent and the response headers read.
|
||
|
+ * FIXME
|
||
|
*
|
||
|
- * If @msg gets a non-2xx result, the first read (or send) will return
|
||
|
- * an error with type %SOUP_INPUT_STREAM_HTTP_ERROR.
|
||
|
- *
|
||
|
- * Internally, #SoupInputStream is implemented using asynchronous I/O,
|
||
|
- * so if you are using the synchronous API (eg,
|
||
|
- * g_input_stream_read()), you should create a new #GMainContext and
|
||
|
- * set it as the %SOUP_SESSION_ASYNC_CONTEXT property on @session. (If
|
||
|
- * you don't, then synchronous #GInputStream calls will cause the main
|
||
|
- * loop to be run recursively.) The async #GInputStream API works fine
|
||
|
- * with %SOUP_SESSION_ASYNC_CONTEXT either set or unset.
|
||
|
*
|
||
|
* Returns: a new #GInputStream.
|
||
|
**/
|
||
|
@@ -211,17 +223,15 @@ soup_input_stream_new (SoupSession *session, SoupMessage *msg)
|
||
|
priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
|
||
|
|
||
|
priv->session = g_object_ref (session);
|
||
|
- priv->async_context = soup_session_get_async_context (session);
|
||
|
priv->msg = g_object_ref (msg);
|
||
|
-
|
||
|
+
|
||
|
g_signal_connect (msg, "got_headers",
|
||
|
- G_CALLBACK (soup_input_stream_got_headers), stream);
|
||
|
+ G_CALLBACK (soup_input_stream_got_headers), stream);
|
||
|
g_signal_connect (msg, "got_chunk",
|
||
|
- G_CALLBACK (soup_input_stream_got_chunk), stream);
|
||
|
+ G_CALLBACK (soup_input_stream_got_chunk), stream);
|
||
|
g_signal_connect (msg, "finished",
|
||
|
- G_CALLBACK (soup_input_stream_finished), stream);
|
||
|
+ G_CALLBACK (soup_input_stream_finished), stream);
|
||
|
|
||
|
- soup_input_stream_queue_message (stream);
|
||
|
return G_INPUT_STREAM (stream);
|
||
|
}
|
||
|
|
||
|
@@ -230,6 +240,8 @@ soup_input_stream_got_headers (SoupMessage *msg, gpointer stream)
|
||
|
{
|
||
|
SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
|
||
|
|
||
|
+ g_mutex_lock (priv->lock);
|
||
|
+
|
||
|
/* If the status is unsuccessful, we just ignore the signal and let
|
||
|
* libsoup keep going (eventually either it will requeue the request
|
||
|
* (after handling authentication/redirection), or else the
|
||
|
@@ -239,19 +251,14 @@ soup_input_stream_got_headers (SoupMessage *msg, gpointer stream)
|
||
|
return;
|
||
|
|
||
|
priv->got_headers = TRUE;
|
||
|
- if (!priv->caller_buffer)
|
||
|
- {
|
||
|
- /* Not ready to read the body yet */
|
||
|
- soup_session_pause_message (priv->session, msg);
|
||
|
- }
|
||
|
-
|
||
|
- if (priv->got_headers_cb)
|
||
|
- priv->got_headers_cb (stream);
|
||
|
+ g_cond_signal (priv->cond);
|
||
|
+ g_mutex_unlock (priv->lock);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
-soup_input_stream_got_chunk (SoupMessage *msg, SoupBuffer *chunk_buffer,
|
||
|
- gpointer stream)
|
||
|
+soup_input_stream_got_chunk (SoupMessage *msg,
|
||
|
+ SoupBuffer *chunk_buffer,
|
||
|
+ gpointer stream)
|
||
|
{
|
||
|
SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
|
||
|
const gchar *chunk = chunk_buffer->data;
|
||
|
@@ -263,46 +270,14 @@ soup_input_stream_got_chunk (SoupMessage *msg, SoupBuffer *chunk_buffer,
|
||
|
if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
|
||
|
return;
|
||
|
|
||
|
- /* Sanity check */
|
||
|
- if (priv->caller_bufsize == 0 || priv->leftover_bufsize != 0)
|
||
|
- g_warning ("soup_input_stream_got_chunk called again before previous chunk was processed");
|
||
|
-
|
||
|
- /* Copy what we can into priv->caller_buffer */
|
||
|
- if (priv->caller_bufsize - priv->caller_nread > 0)
|
||
|
- {
|
||
|
- gsize nread = MIN (chunk_size, priv->caller_bufsize - priv->caller_nread);
|
||
|
-
|
||
|
- memcpy (priv->caller_buffer + priv->caller_nread, chunk, nread);
|
||
|
- priv->caller_nread += nread;
|
||
|
- priv->offset += nread;
|
||
|
- chunk += nread;
|
||
|
- chunk_size -= nread;
|
||
|
- }
|
||
|
-
|
||
|
- if (chunk_size > 0)
|
||
|
- {
|
||
|
- /* Copy the rest into priv->leftover_buffer. If there's already
|
||
|
- * some data there, realloc and append. Otherwise just copy.
|
||
|
- */
|
||
|
- if (priv->leftover_bufsize)
|
||
|
- {
|
||
|
- priv->leftover_buffer = g_realloc (priv->leftover_buffer,
|
||
|
- priv->leftover_bufsize + chunk_size);
|
||
|
- memcpy (priv->leftover_buffer + priv->leftover_bufsize,
|
||
|
- chunk, chunk_size);
|
||
|
- priv->leftover_bufsize += chunk_size;
|
||
|
- }
|
||
|
- else
|
||
|
- {
|
||
|
- priv->leftover_bufsize = chunk_size;
|
||
|
- priv->leftover_buffer = g_memdup (chunk, chunk_size);
|
||
|
- priv->leftover_offset = 0;
|
||
|
- }
|
||
|
- }
|
||
|
+ g_output_stream_write_all (priv->out,
|
||
|
+ chunk,
|
||
|
+ chunk_size,
|
||
|
+ NULL,
|
||
|
+ NULL,
|
||
|
+ NULL);
|
||
|
|
||
|
- soup_session_pause_message (priv->session, msg);
|
||
|
- if (priv->got_chunk_cb)
|
||
|
- priv->got_chunk_cb (stream);
|
||
|
+ /* FIXME: handle errors */
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
@@ -310,71 +285,12 @@ soup_input_stream_finished (SoupMessage *msg, gpointer stream)
|
||
|
{
|
||
|
SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
|
||
|
|
||
|
+ g_mutex_lock (priv->lock);
|
||
|
priv->finished = TRUE;
|
||
|
-
|
||
|
- if (priv->finished_cb)
|
||
|
- priv->finished_cb (stream);
|
||
|
-}
|
||
|
-
|
||
|
-static gboolean
|
||
|
-soup_input_stream_cancelled (GIOChannel *chan, GIOCondition condition,
|
||
|
- gpointer stream)
|
||
|
-{
|
||
|
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
|
||
|
-
|
||
|
- priv->cancel_watch = NULL;
|
||
|
-
|
||
|
- soup_session_pause_message (priv->session, priv->msg);
|
||
|
- if (priv->cancelled_cb)
|
||
|
- priv->cancelled_cb (stream);
|
||
|
-
|
||
|
- return FALSE;
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-soup_input_stream_prepare_for_io (GInputStream *stream,
|
||
|
- GCancellable *cancellable,
|
||
|
- guchar *buffer,
|
||
|
- gsize count)
|
||
|
-{
|
||
|
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
|
||
|
- int cancel_fd;
|
||
|
-
|
||
|
- priv->cancellable = cancellable;
|
||
|
- cancel_fd = g_cancellable_get_fd (cancellable);
|
||
|
- if (cancel_fd != -1)
|
||
|
- {
|
||
|
- GIOChannel *chan = g_io_channel_unix_new (cancel_fd);
|
||
|
- priv->cancel_watch = soup_add_io_watch (priv->async_context, chan,
|
||
|
- G_IO_IN | G_IO_ERR | G_IO_HUP,
|
||
|
- soup_input_stream_cancelled,
|
||
|
- stream);
|
||
|
- g_io_channel_unref (chan);
|
||
|
- }
|
||
|
-
|
||
|
- priv->caller_buffer = buffer;
|
||
|
- priv->caller_bufsize = count;
|
||
|
- priv->caller_nread = 0;
|
||
|
-
|
||
|
- if (priv->got_headers)
|
||
|
- soup_session_unpause_message (priv->session, priv->msg);
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-soup_input_stream_done_io (GInputStream *stream)
|
||
|
-{
|
||
|
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
|
||
|
-
|
||
|
- if (priv->cancel_watch)
|
||
|
- {
|
||
|
- g_source_destroy (priv->cancel_watch);
|
||
|
- priv->cancel_watch = NULL;
|
||
|
- g_cancellable_release_fd (priv->cancellable);
|
||
|
- }
|
||
|
- priv->cancellable = NULL;
|
||
|
-
|
||
|
- priv->caller_buffer = NULL;
|
||
|
- priv->caller_bufsize = 0;
|
||
|
+ //g_print ("Finished!\n");
|
||
|
+ g_mem_pipe_close_write (priv->mem_pipe, NULL, NULL);
|
||
|
+ g_cond_signal (priv->cond);
|
||
|
+ g_mutex_unlock (priv->lock);
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
@@ -386,58 +302,10 @@ set_error_if_http_failed (SoupMessage *msg, GError **error)
|
||
|
msg->status_code, msg->reason_phrase);
|
||
|
return TRUE;
|
||
|
}
|
||
|
+
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
-static gsize
|
||
|
-read_from_leftover (SoupInputStreamPrivate *priv,
|
||
|
- gpointer buffer, gsize bufsize)
|
||
|
-{
|
||
|
- gsize nread;
|
||
|
-
|
||
|
- if (priv->leftover_bufsize - priv->leftover_offset <= bufsize)
|
||
|
- {
|
||
|
- nread = priv->leftover_bufsize - priv->leftover_offset;
|
||
|
- memcpy (buffer, priv->leftover_buffer + priv->leftover_offset, nread);
|
||
|
-
|
||
|
- g_free (priv->leftover_buffer);
|
||
|
- priv->leftover_buffer = NULL;
|
||
|
- priv->leftover_bufsize = priv->leftover_offset = 0;
|
||
|
- }
|
||
|
- else
|
||
|
- {
|
||
|
- nread = bufsize;
|
||
|
- memcpy (buffer, priv->leftover_buffer + priv->leftover_offset, nread);
|
||
|
- priv->leftover_offset += nread;
|
||
|
- }
|
||
|
-
|
||
|
- priv->offset += nread;
|
||
|
- return nread;
|
||
|
-}
|
||
|
-
|
||
|
-/* This does the work of soup_input_stream_send(), assuming that the
|
||
|
- * GInputStream pending flag has already been set. It is also used by
|
||
|
- * soup_input_stream_send_async() in some circumstances.
|
||
|
- */
|
||
|
-static gboolean
|
||
|
-soup_input_stream_send_internal (GInputStream *stream,
|
||
|
- GCancellable *cancellable,
|
||
|
- GError **error)
|
||
|
-{
|
||
|
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
|
||
|
-
|
||
|
- soup_input_stream_prepare_for_io (stream, cancellable, NULL, 0);
|
||
|
- while (!priv->finished && !priv->got_headers &&
|
||
|
- !g_cancellable_is_cancelled (cancellable))
|
||
|
- g_main_context_iteration (priv->async_context, TRUE);
|
||
|
- soup_input_stream_done_io (stream);
|
||
|
-
|
||
|
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||
|
- return FALSE;
|
||
|
- else if (set_error_if_http_failed (priv->msg, error))
|
||
|
- return FALSE;
|
||
|
- return TRUE;
|
||
|
-}
|
||
|
|
||
|
/**
|
||
|
* soup_input_stream_send:
|
||
|
@@ -454,54 +322,59 @@ soup_input_stream_send_internal (GInputStream *stream,
|
||
|
* not.
|
||
|
**/
|
||
|
gboolean
|
||
|
-soup_input_stream_send (GInputStream *stream,
|
||
|
- GCancellable *cancellable,
|
||
|
- GError **error)
|
||
|
+soup_input_stream_send (GInputStream *input_stream,
|
||
|
+ GCancellable *cancellable,
|
||
|
+ GError **error)
|
||
|
{
|
||
|
+ SoupInputStream *stream;
|
||
|
+ SoupInputStreamPrivate *priv;
|
||
|
gboolean result;
|
||
|
|
||
|
- g_return_val_if_fail (SOUP_IS_INPUT_STREAM (stream), FALSE);
|
||
|
+ g_return_val_if_fail (SOUP_IS_INPUT_STREAM (input_stream), FALSE);
|
||
|
+
|
||
|
+ stream = SOUP_INPUT_STREAM (input_stream);
|
||
|
+ priv = stream->priv;
|
||
|
|
||
|
- if (!g_input_stream_set_pending (stream, error))
|
||
|
+ if (!g_input_stream_set_pending (input_stream, error))
|
||
|
return FALSE;
|
||
|
- result = soup_input_stream_send_internal (stream, cancellable, error);
|
||
|
- g_input_stream_clear_pending (stream);
|
||
|
+
|
||
|
+ _soup_input_stream_queue_msg_and_wait (stream);
|
||
|
+
|
||
|
+ g_input_stream_clear_pending (input_stream);
|
||
|
+
|
||
|
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||
|
+ return FALSE;
|
||
|
+
|
||
|
+ result = ! set_error_if_http_failed (priv->msg, error);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static gssize
|
||
|
-soup_input_stream_read (GInputStream *stream,
|
||
|
- void *buffer,
|
||
|
- gsize count,
|
||
|
- GCancellable *cancellable,
|
||
|
- GError **error)
|
||
|
+soup_input_stream_read (GInputStream *stream,
|
||
|
+ void *buffer,
|
||
|
+ gsize count,
|
||
|
+ GCancellable *cancellable,
|
||
|
+ GError **error)
|
||
|
{
|
||
|
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
|
||
|
-
|
||
|
- if (priv->finished)
|
||
|
- return 0;
|
||
|
+ SoupInputStream *istream;
|
||
|
+ SoupInputStreamPrivate *priv;
|
||
|
+ gssize nread;
|
||
|
|
||
|
- /* If there is data leftover from a previous read, return it. */
|
||
|
- if (priv->leftover_bufsize)
|
||
|
- return read_from_leftover (priv, buffer, count);
|
||
|
+ g_return_val_if_fail (SOUP_IS_INPUT_STREAM (stream), -1);
|
||
|
+
|
||
|
+ istream = SOUP_INPUT_STREAM (stream);
|
||
|
+ priv = istream->priv;
|
||
|
|
||
|
- /* No leftover data, accept one chunk from the network */
|
||
|
- soup_input_stream_prepare_for_io (stream, cancellable, buffer, count);
|
||
|
- while (!priv->finished && priv->caller_nread == 0 &&
|
||
|
- !g_cancellable_is_cancelled (cancellable))
|
||
|
- g_main_context_iteration (priv->async_context, TRUE);
|
||
|
- soup_input_stream_done_io (stream);
|
||
|
+ nread = g_input_stream_read (priv->in,
|
||
|
+ buffer,
|
||
|
+ count,
|
||
|
+ cancellable,
|
||
|
+ error);
|
||
|
|
||
|
- if (priv->caller_nread > 0)
|
||
|
- return priv->caller_nread;
|
||
|
+ priv->offset += nread;
|
||
|
|
||
|
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||
|
- return -1;
|
||
|
- else if (set_error_if_http_failed (priv->msg, error))
|
||
|
- return -1;
|
||
|
- else
|
||
|
- return 0;
|
||
|
+ return nread;
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
@@ -509,314 +382,25 @@ soup_input_stream_close (GInputStream *stream,
|
||
|
GCancellable *cancellable,
|
||
|
GError **error)
|
||
|
{
|
||
|
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
|
||
|
-
|
||
|
- if (!priv->finished)
|
||
|
- soup_session_cancel_message (priv->session, priv->msg, SOUP_STATUS_CANCELLED);
|
||
|
-
|
||
|
- return TRUE;
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-wrapper_callback (GObject *source_object, GAsyncResult *res,
|
||
|
- gpointer user_data)
|
||
|
-{
|
||
|
- GInputStream *stream = G_INPUT_STREAM (source_object);
|
||
|
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
|
||
|
-
|
||
|
- g_input_stream_clear_pending (stream);
|
||
|
- if (priv->outstanding_callback)
|
||
|
- (*priv->outstanding_callback) (source_object, res, user_data);
|
||
|
- priv->outstanding_callback = NULL;
|
||
|
- g_object_unref (stream);
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-send_async_thread (GSimpleAsyncResult *res,
|
||
|
- GObject *object,
|
||
|
- GCancellable *cancellable)
|
||
|
-{
|
||
|
- GError *error = NULL;
|
||
|
- gboolean success;
|
||
|
-
|
||
|
- success = soup_input_stream_send_internal (G_INPUT_STREAM (object),
|
||
|
- cancellable, &error);
|
||
|
- g_simple_async_result_set_op_res_gboolean (res, success);
|
||
|
- if (error)
|
||
|
- {
|
||
|
- g_simple_async_result_set_from_error (res, error);
|
||
|
- g_error_free (error);
|
||
|
- }
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-soup_input_stream_send_async_in_thread (GInputStream *stream,
|
||
|
- int io_priority,
|
||
|
- GCancellable *cancellable,
|
||
|
- GAsyncReadyCallback callback,
|
||
|
- gpointer user_data)
|
||
|
-{
|
||
|
- GSimpleAsyncResult *res;
|
||
|
-
|
||
|
- res = g_simple_async_result_new (G_OBJECT (stream), callback, user_data,
|
||
|
- soup_input_stream_send_async_in_thread);
|
||
|
- g_simple_async_result_run_in_thread (res, send_async_thread,
|
||
|
- io_priority, cancellable);
|
||
|
- g_object_unref (res);
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-send_async_finished (GInputStream *stream)
|
||
|
-{
|
||
|
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
|
||
|
- GSimpleAsyncResult *result;
|
||
|
- GError *error = NULL;
|
||
|
-
|
||
|
- if (!g_cancellable_set_error_if_cancelled (priv->cancellable, &error))
|
||
|
- set_error_if_http_failed (priv->msg, &error);
|
||
|
-
|
||
|
- priv->got_headers_cb = NULL;
|
||
|
- priv->finished_cb = NULL;
|
||
|
- soup_input_stream_done_io (stream);
|
||
|
-
|
||
|
- result = priv->result;
|
||
|
- priv->result = NULL;
|
||
|
-
|
||
|
- g_simple_async_result_set_op_res_gboolean (result, error == NULL);
|
||
|
- if (error)
|
||
|
- {
|
||
|
- g_simple_async_result_set_from_error (result, error);
|
||
|
- g_error_free (error);
|
||
|
- }
|
||
|
- g_simple_async_result_complete (result);
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-soup_input_stream_send_async_internal (GInputStream *stream,
|
||
|
- int io_priority,
|
||
|
- GCancellable *cancellable,
|
||
|
- GAsyncReadyCallback callback,
|
||
|
- gpointer user_data)
|
||
|
-{
|
||
|
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
|
||
|
-
|
||
|
- g_object_ref (stream);
|
||
|
- priv->outstanding_callback = callback;
|
||
|
-
|
||
|
- /* If the session uses the default GMainContext, then we can do
|
||
|
- * async I/O directly. But if it has its own main context, it's
|
||
|
- * easier to just run it in another thread.
|
||
|
- */
|
||
|
- if (soup_session_get_async_context (priv->session))
|
||
|
- {
|
||
|
- soup_input_stream_send_async_in_thread (stream, io_priority, cancellable,
|
||
|
- wrapper_callback, user_data);
|
||
|
- return;
|
||
|
- }
|
||
|
-
|
||
|
- priv->got_headers_cb = send_async_finished;
|
||
|
- priv->finished_cb = send_async_finished;
|
||
|
-
|
||
|
- soup_input_stream_prepare_for_io (stream, cancellable, NULL, 0);
|
||
|
- priv->result = g_simple_async_result_new (G_OBJECT (stream),
|
||
|
- wrapper_callback, user_data,
|
||
|
- soup_input_stream_send_async);
|
||
|
-}
|
||
|
-
|
||
|
-/**
|
||
|
- * soup_input_stream_send_async:
|
||
|
- * @stream: a #SoupInputStream
|
||
|
- * @io_priority: the io priority of the request.
|
||
|
- * @cancellable: optional #GCancellable object, %NULL to ignore.
|
||
|
- * @callback: callback to call when the request is satisfied
|
||
|
- * @user_data: the data to pass to callback function
|
||
|
- *
|
||
|
- * Asynchronously sends the HTTP request associated with @stream, and
|
||
|
- * reads the response headers. Call this after soup_input_stream_new()
|
||
|
- * and before the first g_input_stream_read_async() if you want to
|
||
|
- * check the HTTP status code before you start reading.
|
||
|
- **/
|
||
|
-void
|
||
|
-soup_input_stream_send_async (GInputStream *stream,
|
||
|
- int io_priority,
|
||
|
- GCancellable *cancellable,
|
||
|
- GAsyncReadyCallback callback,
|
||
|
- gpointer user_data)
|
||
|
-{
|
||
|
- GError *error = NULL;
|
||
|
-
|
||
|
- g_return_if_fail (SOUP_IS_INPUT_STREAM (stream));
|
||
|
-
|
||
|
- if (!g_input_stream_set_pending (stream, &error))
|
||
|
- {
|
||
|
- g_simple_async_report_gerror_in_idle (G_OBJECT (stream),
|
||
|
- callback,
|
||
|
- user_data,
|
||
|
- error);
|
||
|
- g_error_free (error);
|
||
|
- return;
|
||
|
- }
|
||
|
- soup_input_stream_send_async_internal (stream, io_priority, cancellable,
|
||
|
- callback, user_data);
|
||
|
-}
|
||
|
-
|
||
|
-/**
|
||
|
- * soup_input_stream_send_finish:
|
||
|
- * @stream: a #SoupInputStream
|
||
|
- * @result: a #GAsyncResult.
|
||
|
- * @error: a #GError location to store the error occuring, or %NULL to
|
||
|
- * ignore.
|
||
|
- *
|
||
|
- * Finishes a soup_input_stream_send_async() operation.
|
||
|
- *
|
||
|
- * Return value: %TRUE if the message was sent successfully and
|
||
|
- * received a successful status code, %FALSE if not.
|
||
|
- **/
|
||
|
-gboolean
|
||
|
-soup_input_stream_send_finish (GInputStream *stream,
|
||
|
- GAsyncResult *result,
|
||
|
- GError **error)
|
||
|
-{
|
||
|
- GSimpleAsyncResult *simple;
|
||
|
-
|
||
|
- g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
|
||
|
- simple = G_SIMPLE_ASYNC_RESULT (result);
|
||
|
-
|
||
|
- g_return_val_if_fail (g_simple_async_result_get_source_tag (simple) == soup_input_stream_send_async, FALSE);
|
||
|
-
|
||
|
- if (g_simple_async_result_propagate_error (simple, error))
|
||
|
- return FALSE;
|
||
|
-
|
||
|
- return g_simple_async_result_get_op_res_gboolean (simple);
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-read_async_done (GInputStream *stream)
|
||
|
-{
|
||
|
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
|
||
|
- GSimpleAsyncResult *result;
|
||
|
- GError *error = NULL;
|
||
|
-
|
||
|
- result = priv->result;
|
||
|
- priv->result = NULL;
|
||
|
-
|
||
|
- if (g_cancellable_set_error_if_cancelled (priv->cancellable, &error) ||
|
||
|
- set_error_if_http_failed (priv->msg, &error))
|
||
|
- {
|
||
|
- g_simple_async_result_set_from_error (result, error);
|
||
|
- g_error_free (error);
|
||
|
- }
|
||
|
- else
|
||
|
- g_simple_async_result_set_op_res_gssize (result, priv->caller_nread);
|
||
|
-
|
||
|
- priv->got_chunk_cb = NULL;
|
||
|
- priv->finished_cb = NULL;
|
||
|
- priv->cancelled_cb = NULL;
|
||
|
- soup_input_stream_done_io (stream);
|
||
|
-
|
||
|
- g_simple_async_result_complete (result);
|
||
|
- g_object_unref (result);
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-soup_input_stream_read_async (GInputStream *stream,
|
||
|
- void *buffer,
|
||
|
- gsize count,
|
||
|
- int io_priority,
|
||
|
- GCancellable *cancellable,
|
||
|
- GAsyncReadyCallback callback,
|
||
|
- gpointer user_data)
|
||
|
-{
|
||
|
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
|
||
|
- GSimpleAsyncResult *result;
|
||
|
-
|
||
|
- /* If the session uses the default GMainContext, then we can do
|
||
|
- * async I/O directly. But if it has its own main context, we fall
|
||
|
- * back to the async-via-sync-in-another-thread implementation.
|
||
|
- */
|
||
|
- if (soup_session_get_async_context (priv->session))
|
||
|
- {
|
||
|
- G_INPUT_STREAM_CLASS (soup_input_stream_parent_class)->
|
||
|
- read_async (stream, buffer, count, io_priority,
|
||
|
- cancellable, callback, user_data);
|
||
|
- return;
|
||
|
- }
|
||
|
-
|
||
|
- result = g_simple_async_result_new (G_OBJECT (stream),
|
||
|
- callback, user_data,
|
||
|
- soup_input_stream_read_async);
|
||
|
-
|
||
|
- if (priv->finished)
|
||
|
- {
|
||
|
- g_simple_async_result_set_op_res_gssize (result, 0);
|
||
|
- g_simple_async_result_complete_in_idle (result);
|
||
|
- g_object_unref (result);
|
||
|
- return;
|
||
|
- }
|
||
|
-
|
||
|
- if (priv->leftover_bufsize)
|
||
|
- {
|
||
|
- gsize nread = read_from_leftover (priv, buffer, count);
|
||
|
- g_simple_async_result_set_op_res_gssize (result, nread);
|
||
|
- g_simple_async_result_complete_in_idle (result);
|
||
|
- g_object_unref (result);
|
||
|
- return;
|
||
|
- }
|
||
|
-
|
||
|
- priv->result = result;
|
||
|
-
|
||
|
- priv->got_chunk_cb = read_async_done;
|
||
|
- priv->finished_cb = read_async_done;
|
||
|
- priv->cancelled_cb = read_async_done;
|
||
|
- soup_input_stream_prepare_for_io (stream, cancellable, buffer, count);
|
||
|
-}
|
||
|
-
|
||
|
-static gssize
|
||
|
-soup_input_stream_read_finish (GInputStream *stream,
|
||
|
- GAsyncResult *result,
|
||
|
- GError **error)
|
||
|
-{
|
||
|
- GSimpleAsyncResult *simple;
|
||
|
+ SoupInputStream *istream;
|
||
|
+ SoupInputStreamPrivate *priv;
|
||
|
|
||
|
- g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), -1);
|
||
|
- simple = G_SIMPLE_ASYNC_RESULT (result);
|
||
|
- g_return_val_if_fail (g_simple_async_result_get_source_tag (simple) == soup_input_stream_read_async, -1);
|
||
|
+ g_return_val_if_fail (SOUP_IS_INPUT_STREAM (stream), -1);
|
||
|
|
||
|
- return g_simple_async_result_get_op_res_gssize (simple);
|
||
|
-}
|
||
|
+ istream = SOUP_INPUT_STREAM (stream);
|
||
|
+ priv = istream->priv;
|
||
|
|
||
|
-static void
|
||
|
-soup_input_stream_close_async (GInputStream *stream,
|
||
|
- int io_priority,
|
||
|
- GCancellable *cancellable,
|
||
|
- GAsyncReadyCallback callback,
|
||
|
- gpointer user_data)
|
||
|
-{
|
||
|
- GSimpleAsyncResult *result;
|
||
|
- gboolean success;
|
||
|
- GError *error = NULL;
|
||
|
-
|
||
|
- result = g_simple_async_result_new (G_OBJECT (stream),
|
||
|
- callback, user_data,
|
||
|
- soup_input_stream_close_async);
|
||
|
- success = soup_input_stream_close (stream, cancellable, &error);
|
||
|
- g_simple_async_result_set_op_res_gboolean (result, success);
|
||
|
- if (error)
|
||
|
+ g_mutex_lock (priv->lock);
|
||
|
+ if (!priv->finished)
|
||
|
{
|
||
|
- g_simple_async_result_set_from_error (result, error);
|
||
|
- g_error_free (error);
|
||
|
+ soup_session_cancel_message (priv->session,
|
||
|
+ priv->msg,
|
||
|
+ SOUP_STATUS_CANCELLED);
|
||
|
+ g_print ("Cancelling message\n");
|
||
|
}
|
||
|
|
||
|
- g_simple_async_result_complete_in_idle (result);
|
||
|
- g_object_unref (result);
|
||
|
-}
|
||
|
-
|
||
|
-static gboolean
|
||
|
-soup_input_stream_close_finish (GInputStream *stream,
|
||
|
- GAsyncResult *result,
|
||
|
- GError **error)
|
||
|
-{
|
||
|
- /* Failures handled in generic close_finish code */
|
||
|
+ g_mem_pipe_close_read (priv->mem_pipe, cancellable, error);
|
||
|
+ g_mutex_unlock (priv->lock);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
@@ -834,17 +418,17 @@ soup_input_stream_can_seek (GSeekable *seekable)
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
-extern void soup_message_io_cleanup (SoupMessage *msg);
|
||
|
|
||
|
static gboolean
|
||
|
soup_input_stream_seek (GSeekable *seekable,
|
||
|
- goffset offset,
|
||
|
- GSeekType type,
|
||
|
- GCancellable *cancellable,
|
||
|
- GError **error)
|
||
|
+ goffset offset,
|
||
|
+ GSeekType type,
|
||
|
+ GCancellable *cancellable,
|
||
|
+ GError **error)
|
||
|
{
|
||
|
GInputStream *stream = G_INPUT_STREAM (seekable);
|
||
|
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (seekable);
|
||
|
+ SoupInputStream *istream = SOUP_INPUT_STREAM (stream);
|
||
|
+ SoupInputStreamPrivate *priv = istream->priv;
|
||
|
char *range;
|
||
|
|
||
|
if (type == G_SEEK_END)
|
||
|
@@ -862,8 +446,7 @@ soup_input_stream_seek (GSeekable *seekable,
|
||
|
if (!g_input_stream_set_pending (stream, error))
|
||
|
return FALSE;
|
||
|
|
||
|
- soup_session_cancel_message (priv->session, priv->msg, SOUP_STATUS_CANCELLED);
|
||
|
- soup_message_io_cleanup (priv->msg);
|
||
|
+ _soup_input_stream_cancel_msg_and_wait (istream);
|
||
|
|
||
|
switch (type)
|
||
|
{
|
||
|
@@ -889,7 +472,7 @@ soup_input_stream_seek (GSeekable *seekable,
|
||
|
soup_message_headers_append (priv->msg->request_headers, "Range", range);
|
||
|
g_free (range);
|
||
|
|
||
|
- soup_input_stream_queue_message (SOUP_INPUT_STREAM (stream));
|
||
|
+ _soup_input_stream_queue_msg_and_wait (istream);
|
||
|
|
||
|
g_input_stream_clear_pending (stream);
|
||
|
return TRUE;
|
||
|
@@ -922,8 +505,8 @@ soup_input_stream_get_message (GInputStream *stream)
|
||
|
GQuark
|
||
|
soup_http_error_quark (void)
|
||
|
{
|
||
|
- static GQuark error;
|
||
|
- if (!error)
|
||
|
- error = g_quark_from_static_string ("soup_http_error_quark");
|
||
|
- return error;
|
||
|
+ static GQuark error;
|
||
|
+ if (!error)
|
||
|
+ error = g_quark_from_static_string ("soup_http_error_quark");
|
||
|
+ return error;
|
||
|
}
|
||
|
diff --git a/daemon/soup-input-stream.h b/daemon/soup-input-stream.h
|
||
|
index f425291..2d47c7c 100644
|
||
|
--- a/daemon/soup-input-stream.h
|
||
|
+++ b/daemon/soup-input-stream.h
|
||
|
@@ -33,17 +33,22 @@ G_BEGIN_DECLS
|
||
|
|
||
|
typedef struct SoupInputStream SoupInputStream;
|
||
|
typedef struct SoupInputStreamClass SoupInputStreamClass;
|
||
|
+typedef struct SoupInputStreamPrivate SoupInputStreamPrivate;
|
||
|
|
||
|
struct SoupInputStream
|
||
|
{
|
||
|
GInputStream parent;
|
||
|
|
||
|
+ SoupInputStreamPrivate *priv;
|
||
|
+
|
||
|
};
|
||
|
|
||
|
struct SoupInputStreamClass
|
||
|
{
|
||
|
GInputStreamClass parent_class;
|
||
|
|
||
|
+
|
||
|
+
|
||
|
/* Padding for future expansion */
|
||
|
void (*_g_reserved1) (void);
|
||
|
void (*_g_reserved2) (void);
|
||
|
@@ -61,15 +66,6 @@ gboolean soup_input_stream_send (GInputStream *stream,
|
||
|
GCancellable *cancellable,
|
||
|
GError **error);
|
||
|
|
||
|
-void soup_input_stream_send_async (GInputStream *stream,
|
||
|
- int io_priority,
|
||
|
- GCancellable *cancellable,
|
||
|
- GAsyncReadyCallback callback,
|
||
|
- gpointer user_data);
|
||
|
-gboolean soup_input_stream_send_finish (GInputStream *stream,
|
||
|
- GAsyncResult *result,
|
||
|
- GError **error);
|
||
|
-
|
||
|
SoupMessage *soup_input_stream_get_message (GInputStream *stream);
|
||
|
|
||
|
#define SOUP_HTTP_ERROR soup_http_error_quark()
|