summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2012-12-18 12:59:03 (GMT)
committerTomas Bzatek <tbzatek@redhat.com>2012-12-18 13:21:55 (GMT)
commitcac808508f1fcdb3c9c00cdb36ba6053a1f5dbbb (patch)
tree0aee32f6f209a613623aae064afb7062fc72eb92
parent333d9db1d52e61f690bd68bcd70c4affe446724a (diff)
downloadgvfs-cac808508f1fcdb3c9c00cdb36ba6053a1f5dbbb.zip
gvfs-cac808508f1fcdb3c9c00cdb36ba6053a1f5dbbb.tar.xz
http: replace SoupInputStream with SoupRequest
Replace the hacky SoupInputStream with a new GVfsHttpInputStream that is a wrapper around SoupRequest. (We need a wrapper stream rather than just using SoupRequest directly because we want the stream here to be seekable, which requires cancelling and re-sending the HTTP request and getting a new underlying stream.) The http and dav backends still use both a sync and an async SoupSession, even though this is no longer necessary, since changing this would require a lot of rewriting of code that currently works. https://bugzilla.gnome.org/show_bug.cgi?id=687757 Signed-off-by: Tomas Bzatek <tbzatek@redhat.com>
-rw-r--r--daemon/Makefile.am4
-rw-r--r--daemon/gvfsbackenddav.c3
-rw-r--r--daemon/gvfsbackendhttp.c50
-rw-r--r--daemon/gvfshttpinputstream.c586
-rw-r--r--daemon/gvfshttpinputstream.h77
-rw-r--r--daemon/soup-input-stream.c930
-rw-r--r--daemon/soup-input-stream.h80
-rw-r--r--daemon/soup-output-stream.c1
8 files changed, 697 insertions, 1034 deletions
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 7d6e6af..52684fc 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -449,7 +449,7 @@ gvfsd_gphoto2_LDADD = $(libraries) $(GPHOTO2_LIBS) $(HAL_LIBS)
endif
gvfsd_http_SOURCES = \
- soup-input-stream.c soup-input-stream.h \
+ gvfshttpinputstream.c gvfshttpinputstream.h \
gvfsbackendhttp.c gvfsbackendhttp.h \
daemon-main.c daemon-main.h \
daemon-main-generic.c
@@ -465,7 +465,7 @@ gvfsd_http_CPPFLAGS = \
gvfsd_http_LDADD = $(libraries) $(HTTP_LIBS)
gvfsd_dav_SOURCES = \
- soup-input-stream.c soup-input-stream.h \
+ gvfshttpinputstream.c gvfshttpinputstream.h \
soup-output-stream.c soup-output-stream.h \
gvfsbackendhttp.c gvfsbackendhttp.h \
gvfsbackenddav.c gvfsbackenddav.h \
diff --git a/daemon/gvfsbackenddav.c b/daemon/gvfsbackenddav.c
index 02e4234..e5fc4c5 100644
--- a/daemon/gvfsbackenddav.c
+++ b/daemon/gvfsbackenddav.c
@@ -58,7 +58,6 @@
#include "gvfsjobenumerate.h"
#include "gvfsdaemonprotocol.h"
-#include "soup-input-stream.h"
#include "soup-output-stream.h"
#ifdef HAVE_AVAHI
@@ -1954,7 +1953,7 @@ do_mount (GVfsBackend *backend,
g_object_unref (msg_opts);
g_object_unref (msg_stat);
- /* also auth the workaround async session we need for SoupInputStream */
+ /* also auth the async session */
g_signal_connect (G_VFS_BACKEND_HTTP (backend)->session_async, "authenticate",
G_CALLBACK (soup_authenticate_from_data),
data);
diff --git a/daemon/gvfsbackendhttp.c b/daemon/gvfsbackendhttp.c
index a9d69dd..1c0f370 100644
--- a/daemon/gvfsbackendhttp.c
+++ b/daemon/gvfsbackendhttp.c
@@ -33,8 +33,12 @@
#include <glib/gi18n.h>
#include <gio/gio.h>
+#define LIBSOUP_USE_UNSTABLE_REQUEST_API
#include <libsoup/soup-gnome.h>
+#include <libsoup/soup-requester.h>
+
#include "gvfsbackendhttp.h"
+#include "gvfshttpinputstream.h"
#include "gvfsjobopenforread.h"
#include "gvfsjobread.h"
#include "gvfsjobseekread.h"
@@ -49,9 +53,6 @@
#include "gvfsdaemonprotocol.h"
#include "gvfsdaemonutils.h"
-#include "soup-input-stream.h"
-
-
G_DEFINE_TYPE (GVfsBackendHttp, g_vfs_backend_http, G_VFS_TYPE_BACKEND)
static void
@@ -118,6 +119,10 @@ g_vfs_backend_http_init (GVfsBackendHttp *backend)
soup_session_add_feature (backend->session_async, content_decoder);
g_object_unref (content_decoder);
+ /* Request API */
+ soup_session_add_feature_by_type (backend->session, SOUP_TYPE_REQUESTER);
+ soup_session_add_feature_by_type (backend->session_async, SOUP_TYPE_REQUESTER);
+
/* Logging */
debug = g_getenv ("GVFS_HTTP_DEBUG");
if (debug)
@@ -337,6 +342,7 @@ open_for_read_ready (GObject *source_object,
{
GInputStream *stream;
GVfsJob *job;
+ SoupMessage *msg;
gboolean res;
gboolean can_seek;
GError *error;
@@ -345,9 +351,9 @@ open_for_read_ready (GObject *source_object,
error = NULL;
job = G_VFS_JOB (user_data);
- res = soup_input_stream_send_finish (stream,
- result,
- &error);
+ res = g_vfs_http_input_stream_send_finish (stream,
+ result,
+ &error);
if (res == FALSE)
{
g_vfs_job_failed_literal (G_VFS_JOB (job),
@@ -360,6 +366,18 @@ open_for_read_ready (GObject *source_object,
return;
}
+ msg = g_vfs_http_input_stream_get_message (stream);
+ if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
+ {
+ g_vfs_job_failed_from_http_status (G_VFS_JOB (job),
+ msg->status_code,
+ msg->reason_phrase);
+ g_object_unref (msg);
+ g_object_unref (stream);
+ return;
+ }
+ g_object_unref (msg);
+
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);
@@ -387,22 +405,16 @@ http_backend_open_for_read (GVfsBackend *backend,
{
GVfsBackendHttp *op_backend;
GInputStream *stream;
- SoupMessage *msg;
op_backend = G_VFS_BACKEND_HTTP (backend);
- msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
-
- soup_message_body_set_accumulate (msg->response_body, FALSE);
-
- stream = soup_input_stream_new (op_backend->session_async, msg);
- g_object_unref (msg);
+ stream = g_vfs_http_input_stream_new (op_backend->session_async, uri);
- soup_input_stream_send_async (stream,
- G_PRIORITY_DEFAULT,
- job->cancellable,
- open_for_read_ready,
- job);
+ g_vfs_http_input_stream_send_async (stream,
+ G_PRIORITY_DEFAULT,
+ job->cancellable,
+ open_for_read_ready,
+ job);
}
/* *** read () *** */
@@ -690,7 +702,7 @@ try_query_info_on_read (GVfsBackend *backend,
GFileInfo *info,
GFileAttributeMatcher *attribute_matcher)
{
- SoupMessage *msg = soup_input_stream_get_message (G_INPUT_STREAM (handle));
+ SoupMessage *msg = g_vfs_http_input_stream_get_message (G_INPUT_STREAM (handle));
file_info_from_message (msg, info, attribute_matcher);
g_object_unref (msg);
diff --git a/daemon/gvfshttpinputstream.c b/daemon/gvfshttpinputstream.c
new file mode 100644
index 0000000..35d9c64
--- /dev/null
+++ b/daemon/gvfshttpinputstream.c
@@ -0,0 +1,586 @@
+/* gvfshttpinputstream.c: seekable wrapper around SoupRequestHTTP
+ *
+ * Copyright (C) 2006, 2007, 2012 Red Hat, Inc.
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#define LIBSOUP_USE_UNSTABLE_REQUEST_API
+#include <libsoup/soup.h>
+#include <libsoup/soup-requester.h>
+#include <libsoup/soup-request-http.h>
+
+#include "gvfshttpinputstream.h"
+
+static void g_vfs_http_input_stream_seekable_iface_init (GSeekableIface *seekable_iface);
+
+G_DEFINE_TYPE_WITH_CODE (GVfsHttpInputStream, g_vfs_http_input_stream, G_TYPE_INPUT_STREAM,
+ G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
+ g_vfs_http_input_stream_seekable_iface_init))
+
+typedef struct {
+ SoupURI *uri;
+ SoupRequester *requester;
+ SoupRequest *req;
+ SoupMessage *msg;
+ GInputStream *stream;
+
+ char *range;
+ goffset offset;
+
+} GVfsHttpInputStreamPrivate;
+#define G_VFS_HTTP_INPUT_STREAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), G_VFS_TYPE_HTTP_INPUT_STREAM, GVfsHttpInputStreamPrivate))
+
+static void
+g_vfs_http_input_stream_init (GVfsHttpInputStream *stream)
+{
+ ;
+}
+
+static void
+g_vfs_http_input_stream_finalize (GObject *object)
+{
+ GVfsHttpInputStream *stream = G_VFS_HTTP_INPUT_STREAM (object);
+ GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ g_clear_pointer (&priv->uri, soup_uri_free);
+ g_clear_object (&priv->requester);
+ g_clear_object (&priv->req);
+ g_clear_object (&priv->msg);
+ g_clear_object (&priv->stream);
+ g_free (priv->range);
+
+ G_OBJECT_CLASS (g_vfs_http_input_stream_parent_class)->finalize (object);
+}
+
+/**
+ * g_vfs_http_input_stream_new:
+ * @session: a #SoupSession
+ * @uri: a #SoupURI
+ *
+ * Prepares to send a GET request for @uri on @session, and returns a
+ * #GInputStream that can be used to read the response.
+ *
+ * The request will 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 g_vfs_http_input_stream_send() or
+ * g_vfs_http_input_stream_send_async() to force the message to be
+ * sent and the response headers read.
+ *
+ * Returns: a new #GInputStream.
+ **/
+GInputStream *
+g_vfs_http_input_stream_new (SoupSession *session,
+ SoupURI *uri)
+{
+ GVfsHttpInputStream *stream;
+ GVfsHttpInputStreamPrivate *priv;
+
+ stream = g_object_new (G_VFS_TYPE_HTTP_INPUT_STREAM, NULL);
+ priv = G_VFS_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ priv->requester = (SoupRequester *)soup_session_get_feature (session, SOUP_TYPE_REQUESTER);
+ g_object_ref (priv->requester);
+ priv->uri = soup_uri_copy (uri);
+
+ return G_INPUT_STREAM (stream);
+}
+
+static SoupRequest *
+g_vfs_http_input_stream_ensure_request (GInputStream *stream)
+{
+ GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ if (!priv->req)
+ {
+ GError *error = NULL;
+
+ priv->req = soup_requester_request_uri (priv->requester, priv->uri, &error);
+ g_assert_no_error (error);
+ priv->msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (priv->req));
+ priv->offset = 0;
+
+ if (priv->range)
+ soup_message_headers_replace (priv->msg->request_headers, "Range", priv->range);
+ }
+
+ return priv->req;
+}
+
+/**
+ * g_vfs_http_input_stream_send:
+ * @stream: a #GVfsHttpInputStream
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @error: location to store the error occuring, or %NULL to ignore
+ *
+ * Synchronously sends the HTTP request associated with @stream, and
+ * reads the response headers. Call this after g_vfs_http_input_stream_new()
+ * and before the first g_input_stream_read() if you want to check the
+ * HTTP status code before you start reading.
+ *
+ * Return value: %TRUE if msg was successfully sent, %FALSE if not
+ **/
+gboolean
+g_vfs_http_input_stream_send (GInputStream *stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GVfsHttpInputStreamPrivate *priv;
+
+ g_return_val_if_fail (G_VFS_IS_HTTP_INPUT_STREAM (stream), FALSE);
+ priv = G_VFS_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ if (priv->stream)
+ return TRUE;
+
+ if (!g_input_stream_set_pending (stream, error))
+ return FALSE;
+ g_vfs_http_input_stream_ensure_request (stream);
+ priv->stream = soup_request_send (priv->req, cancellable, error);
+ g_input_stream_clear_pending (stream);
+
+ return priv->stream != NULL;
+}
+
+static gssize
+g_vfs_http_input_stream_read (GInputStream *stream,
+ void *buffer,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+ gssize nread;
+
+ if (!priv->stream)
+ {
+ g_vfs_http_input_stream_ensure_request (stream);
+ priv->stream = soup_request_send (priv->req, cancellable, error);
+ if (!priv->stream)
+ return -1;
+ }
+
+ nread = g_input_stream_read (priv->stream, buffer, count, cancellable, error);
+ if (nread > 0)
+ priv->offset += nread;
+ return nread;
+}
+
+static gboolean
+g_vfs_http_input_stream_close (GInputStream *stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ if (priv->stream)
+ {
+ if (!g_input_stream_close (priv->stream, cancellable, error))
+ return FALSE;
+ g_clear_object (&priv->stream);
+ }
+
+ return TRUE;
+}
+
+static void
+send_callback (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = user_data;
+ GInputStream *http_stream = g_task_get_source_object (task);
+ GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM_GET_PRIVATE (http_stream);
+ GError *error = NULL;
+
+ g_input_stream_clear_pending (http_stream);
+
+ priv->stream = soup_request_send_finish (SOUP_REQUEST (object), result, &error);
+ if (priv->stream)
+ g_task_return_boolean (task, TRUE);
+ else
+ g_task_return_error (task, error);
+ g_object_unref (task);
+}
+
+/**
+ * g_vfs_http_input_stream_send_async:
+ * @stream: a #GVfsHttpInputStream
+ * @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 g_vfs_http_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
+g_vfs_http_input_stream_send_async (GInputStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsHttpInputStreamPrivate *priv;
+ GError *error = NULL;
+ GTask *task;
+
+ g_return_if_fail (G_VFS_IS_HTTP_INPUT_STREAM (stream));
+ priv = G_VFS_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ task = g_task_new (stream, cancellable, callback, user_data);
+ g_task_set_priority (task, io_priority);
+
+ if (priv->stream)
+ {
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+ }
+
+ if (!g_input_stream_set_pending (stream, &error))
+ {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ g_vfs_http_input_stream_ensure_request (stream);
+ soup_request_send_async (priv->req, cancellable,
+ send_callback, task);
+}
+
+/**
+ * g_vfs_http_input_stream_send_finish:
+ * @stream: a #GVfsHttpInputStream
+ * @result: a #GAsyncResult.
+ * @error: a #GError location to store the error occuring, or %NULL to
+ * ignore.
+ *
+ * Finishes a g_vfs_http_input_stream_send_async() operation.
+ *
+ * Return value: %TRUE if the message was sent successfully, %FALSE if
+ * not.
+ **/
+gboolean
+g_vfs_http_input_stream_send_finish (GInputStream *stream,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void
+read_callback (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = user_data;
+ GInputStream *vfsstream = g_task_get_source_object (task);
+ GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM_GET_PRIVATE (vfsstream);
+ GError *error = NULL;
+ gssize nread;
+
+ nread = g_input_stream_read_finish (G_INPUT_STREAM (object), result, &error);
+ if (nread >= 0)
+ {
+ priv->offset += nread;
+ g_task_return_int (task, nread);
+ }
+ else
+ g_task_return_error (task, error);
+ g_object_unref (task);
+}
+
+typedef struct {
+ gpointer buffer;
+ gsize count;
+} ReadAfterSendData;
+
+static void
+read_send_callback (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = user_data;
+ GInputStream *vfsstream = g_task_get_source_object (task);
+ GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM_GET_PRIVATE (vfsstream);
+ ReadAfterSendData *rasd = g_task_get_task_data (task);
+ GError *error = NULL;
+
+ if (!soup_request_send_finish (SOUP_REQUEST (object), result, &error))
+ {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+ if (!SOUP_STATUS_IS_SUCCESSFUL (priv->msg->status_code))
+ {
+ g_task_return_new_error (task,
+ SOUP_HTTP_ERROR,
+ priv->msg->status_code,
+ "%s", priv->msg->reason_phrase);
+ g_object_unref (task);
+ return;
+ }
+
+ g_input_stream_read_async (priv->stream, rasd->buffer, rasd->count,
+ g_task_get_priority (task),
+ g_task_get_cancellable (task),
+ read_callback, task);
+}
+
+static void
+g_vfs_http_input_stream_read_async (GInputStream *stream,
+ void *buffer,
+ gsize count,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+ GError *error = NULL;
+ GTask *task;
+
+ task = g_task_new (stream, cancellable, callback, user_data);
+ g_task_set_priority (task, io_priority);
+
+ if (!priv->stream)
+ {
+ ReadAfterSendData *rasd;
+
+ rasd = g_new (ReadAfterSendData, 1);
+ rasd->buffer = buffer;
+ rasd->count = count;
+ g_task_set_task_data (task, rasd, g_free);
+
+ g_vfs_http_input_stream_ensure_request (stream);
+ soup_request_send_async (priv->req, cancellable,
+ read_send_callback, task);
+ return;
+ }
+
+ g_input_stream_read_async (priv->stream, buffer, count, io_priority,
+ cancellable, read_callback, task);
+}
+
+static gssize
+g_vfs_http_input_stream_read_finish (GInputStream *stream,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (result, stream), -1);
+
+ return g_task_propagate_int (G_TASK (result), error);
+}
+
+static void
+close_callback (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = user_data;
+ GError *error = NULL;
+
+ if (g_input_stream_close_finish (G_INPUT_STREAM (object), result, &error))
+ g_task_return_boolean (task, TRUE);
+ else
+ g_task_return_error (task, error);
+ g_object_unref (task);
+}
+
+static void
+g_vfs_http_input_stream_close_async (GInputStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+ GError *error = NULL;
+ GTask *task;
+
+ task = g_task_new (stream, cancellable, callback, user_data);
+ g_task_set_priority (task, io_priority);
+
+ if (priv->stream == NULL)
+ {
+ g_task_return_boolean (task, TRUE);
+ return;
+ }
+
+ g_input_stream_close_async (priv->stream, io_priority,
+ cancellable, close_callback, task);
+}
+
+static gboolean
+g_vfs_http_input_stream_close_finish (GInputStream *stream,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (result, stream), -1);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static goffset
+g_vfs_http_input_stream_tell (GSeekable *seekable)
+{
+ GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM_GET_PRIVATE (seekable);
+
+ return priv->offset;
+}
+
+static gboolean
+g_vfs_http_input_stream_can_seek (GSeekable *seekable)
+{
+ return TRUE;
+}
+
+static gboolean
+g_vfs_http_input_stream_seek (GSeekable *seekable,
+ goffset offset,
+ GSeekType type,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GInputStream *stream = G_INPUT_STREAM (seekable);
+ GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM_GET_PRIVATE (seekable);
+
+ if (type == G_SEEK_END && priv->msg)
+ {
+ goffset content_length = soup_message_headers_get_content_length (priv->msg->response_headers);
+
+ if (content_length)
+ {
+ type = G_SEEK_SET;
+ offset = content_length - offset;
+ }
+ }
+
+ if (type == G_SEEK_END)
+ {
+ /* We could send "bytes=-offset", but since we don't know the
+ * Content-Length, we wouldn't be able to answer a tell()
+ * properly after that. We could maybe find the Content-Length
+ * by doing a HEAD... but that would require blocking.
+ */
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ "G_SEEK_END not supported");
+ return FALSE;
+ }
+
+ if (!g_input_stream_set_pending (stream, error))
+ return FALSE;
+
+ if (priv->stream)
+ {
+ if (!g_input_stream_close (priv->stream, NULL, error))
+ return FALSE;
+ g_clear_object (&priv->stream);
+ }
+
+ g_clear_pointer (&priv->range, g_free);
+
+ switch (type)
+ {
+ case G_SEEK_CUR:
+ offset += priv->offset;
+ /* fall through */
+
+ case G_SEEK_SET:
+ priv->range = g_strdup_printf ("bytes=%"G_GUINT64_FORMAT"-", (guint64)offset);
+ priv->offset = offset;
+ break;
+
+ case G_SEEK_END:
+ g_return_val_if_reached (FALSE);
+ break;
+
+ default:
+ g_return_val_if_reached (FALSE);
+ }
+
+ g_input_stream_clear_pending (stream);
+ return TRUE;
+}
+
+static gboolean
+g_vfs_http_input_stream_can_truncate (GSeekable *seekable)
+{
+ return FALSE;
+}
+
+static gboolean
+g_vfs_http_input_stream_truncate (GSeekable *seekable,
+ goffset offset,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ "Truncate not allowed on input stream");
+ return FALSE;
+}
+
+SoupMessage *
+g_vfs_http_input_stream_get_message (GInputStream *stream)
+{
+ GVfsHttpInputStreamPrivate *priv = G_VFS_HTTP_INPUT_STREAM_GET_PRIVATE (stream);
+
+ g_vfs_http_input_stream_ensure_request (stream);
+ return g_object_ref (priv->msg);
+}
+
+
+static void
+g_vfs_http_input_stream_class_init (GVfsHttpInputStreamClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GVfsHttpInputStreamPrivate));
+
+ gobject_class->finalize = g_vfs_http_input_stream_finalize;
+
+ stream_class->read_fn = g_vfs_http_input_stream_read;
+ stream_class->close_fn = g_vfs_http_input_stream_close;
+ stream_class->read_async = g_vfs_http_input_stream_read_async;
+ stream_class->read_finish = g_vfs_http_input_stream_read_finish;
+ stream_class->close_async = g_vfs_http_input_stream_close_async;
+ stream_class->close_finish = g_vfs_http_input_stream_close_finish;
+}
+
+static void
+g_vfs_http_input_stream_seekable_iface_init (GSeekableIface *seekable_iface)
+{
+ seekable_iface->tell = g_vfs_http_input_stream_tell;
+ seekable_iface->can_seek = g_vfs_http_input_stream_can_seek;
+ seekable_iface->seek = g_vfs_http_input_stream_seek;
+ seekable_iface->can_truncate = g_vfs_http_input_stream_can_truncate;
+ seekable_iface->truncate_fn = g_vfs_http_input_stream_truncate;
+}
diff --git a/daemon/gvfshttpinputstream.h b/daemon/gvfshttpinputstream.h
new file mode 100644
index 0000000..dbd06d9
--- /dev/null
+++ b/daemon/gvfshttpinputstream.h
@@ -0,0 +1,77 @@
+/* Copyright (C) 2006, 2007, 2012 Red Hat, Inc.
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __G_VFS_HTTP_INPUT_STREAM_H__
+#define __G_VFS_HTTP_INPUT_STREAM_H__
+
+#include <gio/gio.h>
+#include <libsoup/soup-types.h>
+
+G_BEGIN_DECLS
+
+#define G_VFS_TYPE_HTTP_INPUT_STREAM (g_vfs_http_input_stream_get_type ())
+#define G_VFS_HTTP_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_VFS_TYPE_HTTP_INPUT_STREAM, GVfsHttpInputStream))
+#define G_VFS_HTTP_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_VFS_TYPE_HTTP_INPUT_STREAM, GVfsHttpInputStreamClass))
+#define G_VFS_IS_HTTP_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_VFS_TYPE_HTTP_INPUT_STREAM))
+#define G_VFS_IS_HTTP_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_VFS_TYPE_HTTP_INPUT_STREAM))
+#define G_VFS_HTTP_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_VFS_TYPE_HTTP_INPUT_STREAM, GVfsHttpInputStreamClass))
+
+typedef struct GVfsHttpInputStream GVfsHttpInputStream;
+typedef struct GVfsHttpInputStreamClass GVfsHttpInputStreamClass;
+
+struct GVfsHttpInputStream
+{
+ GInputStream parent;
+
+};
+
+struct GVfsHttpInputStreamClass
+{
+ GInputStreamClass parent_class;
+
+ /* Padding for future expansion */
+ void (*_g_reserved1) (void);
+ void (*_g_reserved2) (void);
+ void (*_g_reserved3) (void);
+ void (*_g_reserved4) (void);
+ void (*_g_reserved5) (void);
+};
+
+GType g_vfs_http_input_stream_get_type (void) G_GNUC_CONST;
+
+GInputStream *g_vfs_http_input_stream_new (SoupSession *session,
+ SoupURI *uri);
+
+gboolean g_vfs_http_input_stream_send (GInputStream *stream,
+ GCancellable *cancellable,
+ GError **error);
+
+void g_vfs_http_input_stream_send_async (GInputStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean g_vfs_http_input_stream_send_finish (GInputStream *stream,
+ GAsyncResult *result,
+ GError **error);
+
+SoupMessage *g_vfs_http_input_stream_get_message (GInputStream *stream);
+
+G_END_DECLS
+
+#endif /* __G_VFS_HTTP_INPUT_STREAM_H__ */
diff --git a/daemon/soup-input-stream.c b/daemon/soup-input-stream.c
deleted file mode 100644
index 18d576d..0000000
--- a/daemon/soup-input-stream.c
+++ /dev/null
@@ -1,930 +0,0 @@
-/* soup-input-stream.c, based on gsocketinputstream.c
- *
- * Copyright (C) 2006-2007 Red Hat, Inc.
- *
- * 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., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include <config.h>
-
-#include <string.h>
-
-#include <glib.h>
-#include <gio/gio.h>
-
-#include <libsoup/soup.h>
-
-#include "soup-input-stream.h"
-
-static void soup_input_stream_seekable_iface_init (GSeekableIface *seekable_iface);
-
-G_DEFINE_TYPE_WITH_CODE (SoupInputStream, soup_input_stream, G_TYPE_INPUT_STREAM,
- G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
- soup_input_stream_seekable_iface_init))
-
-typedef void (*SoupInputStreamCallback) (GInputStream *);
-
-typedef struct {
- 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;
-
- guchar *leftover_buffer;
- gsize leftover_bufsize, leftover_offset;
-
- 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))
-
-
-static gssize soup_input_stream_read (GInputStream *stream,
- void *buffer,
- gsize count,
- GCancellable *cancellable,
- GError **error);
-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);
-
-static gboolean soup_input_stream_can_seek (GSeekable *seekable);
-static gboolean soup_input_stream_seek (GSeekable *seekable,
- goffset offset,
- GSeekType type,
- GCancellable *cancellable,
- GError **error);
-
-static gboolean soup_input_stream_can_truncate (GSeekable *seekable);
-static gboolean soup_input_stream_truncate (GSeekable *seekable,
- goffset offset,
- GCancellable *cancellable,
- GError **error);
-
-static void soup_input_stream_got_headers (SoupMessage *msg, gpointer stream);
-static void soup_input_stream_got_chunk (SoupMessage *msg, SoupBuffer *chunk, gpointer stream);
-static void soup_input_stream_finished (SoupMessage *msg, gpointer stream);
-
-static void
-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_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 (G_OBJECT_CLASS (soup_input_stream_parent_class)->finalize)
- (*G_OBJECT_CLASS (soup_input_stream_parent_class)->finalize) (object);
-}
-
-static void
-soup_input_stream_class_init (SoupInputStreamClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (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->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->can_truncate = soup_input_stream_can_truncate;
- seekable_iface->truncate_fn = soup_input_stream_truncate;
-}
-
-static void
-soup_input_stream_init (SoupInputStream *stream)
-{
- ;
-}
-
-static void
-soup_input_stream_queue_message (SoupInputStream *stream)
-{
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
-
- 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);
-}
-
-/**
- * soup_input_stream_new:
- * @session: the #SoupSession to use
- * @msg: the #SoupMessage whose response will be streamed
- *
- * 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.
- *
- * 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.
- **/
-GInputStream *
-soup_input_stream_new (SoupSession *session, SoupMessage *msg)
-{
- SoupInputStream *stream;
- SoupInputStreamPrivate *priv;
-
- g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
-
- stream = g_object_new (SOUP_TYPE_INPUT_STREAM, NULL);
- 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_signal_connect (msg, "got_chunk",
- G_CALLBACK (soup_input_stream_got_chunk), stream);
- g_signal_connect (msg, "finished",
- G_CALLBACK (soup_input_stream_finished), stream);
-
- soup_input_stream_queue_message (stream);
- return G_INPUT_STREAM (stream);
-}
-
-static void
-soup_input_stream_got_headers (SoupMessage *msg, gpointer stream)
-{
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
-
- /* 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
- * "finished" handler will run).
- */
- if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
- 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);
-}
-
-static void
-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;
- gsize chunk_size = chunk_buffer->length;
-
- /* We only pay attention to the chunk if it's part of a successful
- * response.
- */
- 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;
- }
- }
-
- soup_session_pause_message (priv->session, msg);
- if (priv->got_chunk_cb)
- priv->got_chunk_cb (stream);
-}
-
-static void
-soup_input_stream_finished (SoupMessage *msg, gpointer stream)
-{
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
-
- 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;
-}
-
-static gboolean
-set_error_if_http_failed (SoupMessage *msg, GError **error)
-{
- if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
- {
- g_set_error_literal (error, SOUP_HTTP_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:
- * @stream: a #SoupInputStream
- * @cancellable: optional #GCancellable object, %NULL to ignore.
- * @error: location to store the error occuring, or %NULL to ignore
- *
- * Synchronously 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() if you want to check the
- * HTTP status code before you start reading.
- *
- * Return value: %TRUE if msg has a successful (2xx) status, %FALSE if
- * not.
- **/
-gboolean
-soup_input_stream_send (GInputStream *stream,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean result;
-
- g_return_val_if_fail (SOUP_IS_INPUT_STREAM (stream), FALSE);
-
- if (!g_input_stream_set_pending (stream, error))
- return FALSE;
- result = soup_input_stream_send_internal (stream, cancellable, error);
- g_input_stream_clear_pending (stream);
-
- return result;
-}
-
-static gssize
-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;
-
- /* If there is data leftover from a previous read, return it. */
- if (priv->leftover_bufsize)
- return read_from_leftover (priv, buffer, count);
-
- /* 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);
-
- if (priv->caller_nread > 0)
- return priv->caller_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;
-}
-
-static gboolean
-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);
- g_object_unref (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;
-
- 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);
-
- return g_simple_async_result_get_op_res_gssize (simple);
-}
-
-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_simple_async_result_set_from_error (result, error);
- g_error_free (error);
- }
-
- 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 */
- return TRUE;
-}
-
-static goffset
-soup_input_stream_tell (GSeekable *seekable)
-{
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (seekable);
-
- return priv->offset;
-}
-
-static gboolean
-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)
-{
- GInputStream *stream = G_INPUT_STREAM (seekable);
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (seekable);
- char *range;
-
- if (type == G_SEEK_END)
- {
- /* FIXME: we could send "bytes=-offset", but unless we know the
- * Content-Length, we wouldn't be able to answer a tell() properly.
- * We could find the Content-Length by doing a HEAD...
- */
-
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
- "G_SEEK_END not currently supported");
- return FALSE;
- }
-
- 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);
-
- switch (type)
- {
- case G_SEEK_CUR:
- offset += priv->offset;
- /* fall through */
-
- case G_SEEK_SET:
- range = g_strdup_printf ("bytes=%"G_GUINT64_FORMAT"-", (guint64)offset);
- priv->offset = offset;
- break;
-
- case G_SEEK_END:
- range = NULL; /* keep compilers happy */
- g_return_val_if_reached (FALSE);
- break;
-
- default:
- g_return_val_if_reached (FALSE);
- }
-
- soup_message_headers_remove (priv->msg->request_headers, "Range");
- soup_message_headers_append (priv->msg->request_headers, "Range", range);
- g_free (range);
-
- soup_input_stream_queue_message (SOUP_INPUT_STREAM (stream));
-
- g_input_stream_clear_pending (stream);
- return TRUE;
-}
-
-static gboolean
-soup_input_stream_can_truncate (GSeekable *seekable)
-{
- return FALSE;
-}
-
-static gboolean
-soup_input_stream_truncate (GSeekable *seekable,
- goffset offset,
- GCancellable *cancellable,
- GError **error)
-{
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
- "Truncate not allowed on input stream");
- return FALSE;
-}
-
-SoupMessage *
-soup_input_stream_get_message (GInputStream *stream)
-{
- SoupInputStreamPrivate *priv = SOUP_INPUT_STREAM_GET_PRIVATE (stream);
- return priv->msg ? g_object_ref (priv->msg) : NULL;
-}
-
-GQuark
-soup_http_error_quark (void)
-{
- 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
deleted file mode 100644
index 1f98f9a..0000000
--- a/daemon/soup-input-stream.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* Copyright (C) 2006-2007 Red Hat, Inc.
- *
- * 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., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef __SOUP_INPUT_STREAM_H__
-#define __SOUP_INPUT_STREAM_H__
-
-#include <gio/gio.h>
-#include <libsoup/soup-types.h>
-
-G_BEGIN_DECLS
-
-#define SOUP_TYPE_INPUT_STREAM (soup_input_stream_get_type ())
-#define SOUP_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SOUP_TYPE_INPUT_STREAM, SoupInputStream))
-#define SOUP_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SOUP_TYPE_INPUT_STREAM, SoupInputStreamClass))
-#define SOUP_IS_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SOUP_TYPE_INPUT_STREAM))
-#define SOUP_IS_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SOUP_TYPE_INPUT_STREAM))
-#define SOUP_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SOUP_TYPE_INPUT_STREAM, SoupInputStreamClass))
-
-typedef struct SoupInputStream SoupInputStream;
-typedef struct SoupInputStreamClass SoupInputStreamClass;
-
-struct SoupInputStream
-{
- GInputStream parent;
-
-};
-
-struct SoupInputStreamClass
-{
- GInputStreamClass parent_class;
-
- /* Padding for future expansion */
- void (*_g_reserved1) (void);
- void (*_g_reserved2) (void);
- void (*_g_reserved3) (void);
- void (*_g_reserved4) (void);
- void (*_g_reserved5) (void);
-};
-
-GType soup_input_stream_get_type (void) G_GNUC_CONST;
-
-GInputStream *soup_input_stream_new (SoupSession *session,
- SoupMessage *msg);
-
-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()
-GQuark soup_http_error_quark (void);
-
-G_END_DECLS
-
-#endif /* __SOUP_INPUT_STREAM_H__ */
diff --git a/daemon/soup-output-stream.c b/daemon/soup-output-stream.c
index 47109e7..0231776 100644
--- a/daemon/soup-output-stream.c
+++ b/daemon/soup-output-stream.c
@@ -28,7 +28,6 @@
#include <libsoup/soup.h>
#include "soup-output-stream.h"
-#include "soup-input-stream.h"
G_DEFINE_TYPE (SoupOutputStream, soup_output_stream, G_TYPE_OUTPUT_STREAM)