gvfs r1107 - in trunk: . daemon



Author: danw
Date: Sat Jan 12 02:36:58 2008
New Revision: 1107
URL: http://svn.gnome.org/viewvc/gvfs?rev=1107&view=rev

Log:
	* daemon/soup-input-stream.c: implement GSeekable (a bit hackishly
	due to a bug in libsoup 2.2.x)

	* daemon/gvfsbackendhttp.c (try_seek_on_read): implement


Modified:
   trunk/ChangeLog
   trunk/daemon/gvfsbackendhttp.c
   trunk/daemon/soup-input-stream.c

Modified: trunk/daemon/gvfsbackendhttp.c
==============================================================================
--- trunk/daemon/gvfsbackendhttp.c	(original)
+++ trunk/daemon/gvfsbackendhttp.c	Sat Jan 12 02:36:58 2008
@@ -272,6 +272,39 @@
   return TRUE;
 }
 
+static gboolean
+try_seek_on_read (GVfsBackend *backend,
+                  GVfsJobSeekRead *job,
+                  GVfsBackendHandle handle,
+                  goffset    offset,
+                  GSeekType  type)
+{
+  GVfsBackendHttp *op_backend;
+  GInputStream    *stream;
+  GError          *error = NULL;
+
+  op_backend = G_VFS_BACKEND_HTTP (backend);
+  stream = G_INPUT_STREAM (handle);
+
+  if (!g_seekable_seek (G_SEEKABLE (stream), offset, type,
+                        G_VFS_JOB (job)->cancellable, &error))
+    {
+      g_vfs_job_failed (G_VFS_JOB (job),
+                        error->domain,
+                        error->code,
+                        error->message);
+      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,
@@ -350,6 +383,7 @@
   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->try_query_info    = try_query_info;
 

Modified: trunk/daemon/soup-input-stream.c
==============================================================================
--- trunk/daemon/soup-input-stream.c	(original)
+++ trunk/daemon/soup-input-stream.c	Sat Jan 12 02:36:58 2008
@@ -29,7 +29,11 @@
 
 #include "soup-input-stream.h"
 
-G_DEFINE_TYPE (SoupInputStream, soup_input_stream, G_TYPE_INPUT_STREAM);
+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 *);
 
@@ -38,6 +42,7 @@
   GMainContext *async_context;
   SoupMessage *msg;
   gboolean got_headers;
+  goffset offset;
 
   GCancellable *cancellable;
   GSource *cancel_watch;
@@ -85,6 +90,21 @@
 						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, gpointer stream);
 static void soup_input_stream_finished (SoupMessage *msg, gpointer stream);
@@ -128,6 +148,16 @@
 }
 
 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)
 {
   ;
@@ -237,6 +267,7 @@
 
       memcpy (priv->caller_buffer + priv->caller_nread, chunk, nread);
       priv->caller_nread += nread;
+      priv->offset += nread;
       chunk += nread;
       chunk_size -= nread;
     }
@@ -369,6 +400,8 @@
       memcpy (buffer, priv->leftover_buffer + priv->leftover_offset, nread);
       priv->leftover_offset += nread;
     }
+
+  priv->offset += nread;
   return nread;
 }
 
@@ -768,6 +801,93 @@
   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 (!g_input_stream_set_pending (stream, error))
+      return FALSE;
+
+  if (priv->msg->status != SOUP_MESSAGE_STATUS_FINISHED)
+    soup_session_cancel_message (priv->session, 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:
+      /* 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 (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+		   "G_SEEK_END not currently supported");
+      break;
+
+    default:
+      g_return_val_if_reached (FALSE);
+    }
+
+  soup_message_remove_header (priv->msg->request_headers, "Range");
+  soup_message_add_header (priv->msg->request_headers, "Range", range);
+  g_free (range);
+
+  soup_session_cancel_message (priv->session, priv->msg);
+  soup_message_io_cleanup (priv->msg);
+  g_object_ref (priv->msg);
+  soup_session_queue_message (priv->session, priv->msg, NULL, NULL);
+
+  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 (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+	       "Truncate not allowed on input stream");
+  return FALSE;
+}
+
 GQuark
 soup_http_error_quark (void)
 {



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