Implemented seek() and tell() for r/o streams of 'http'.
authorshort <>
Mon, 1 Sep 2003 16:31:00 +0000 (16:31 +0000)
committershort <>
Mon, 1 Sep 2003 16:31:00 +0000 (16:31 +0000)
modules/http-method.c

index 317513d..cba1274 100644 (file)
@@ -100,6 +100,9 @@ http_debug_printf (char *fmt, ...)
 /* Standard HTTP proxy port */
 #define DEFAULT_HTTP_PROXY_PORT 8080
 
+/* Maximum amount of data to read if seek()ed forward. Otherwise make a new connection. */
+#define MAX_BUFFER_SEEK_SKIP_READ      0x10000
+
 /* GConf paths and keys */
 #define PATH_GCONF_GNOME_VFS "/system/http_proxy"
 #define ITEM_GCONF_HTTP_PROXY_PORT "port"
@@ -211,8 +214,11 @@ typedef struct {
        /* File info for this file */
        GnomeVFSFileInfo *file_info;
 
-       /* Bytes read so far.  */
-       GnomeVFSFileSize bytes_read;
+       /* File offset of current pointer of 'socket_buffer'. */
+       GnomeVFSFileOffset socket_buffer_offset;
+
+       /* Offset; Current file position. */
+       GnomeVFSFileOffset offset;
 
        /* Bytes to be written... */
        GByteArray *to_be_written;
@@ -1825,7 +1831,7 @@ do_close (GnomeVFSMethod *method,
        } else {
                result = GNOME_VFS_OK;
        }
-       
+
        http_handle_close (old_handle, context);
        g_free (old_handle);
        
@@ -1840,7 +1846,7 @@ do_write (GnomeVFSMethod *method,
          GnomeVFSMethodHandle *method_handle,
          gconstpointer buffer,
          GnomeVFSFileSize num_bytes,
-         GnomeVFSFileSize *bytes_read,
+         GnomeVFSFileSize *bytes_written,
          GnomeVFSContext *context)
 {
        HttpFileHandle *handle;
@@ -1849,11 +1855,14 @@ do_write (GnomeVFSMethod *method,
 
        handle = (HttpFileHandle *) method_handle;
 
+       if (handle->offset != 0)
+               return GNOME_VFS_ERROR_NOT_SUPPORTED;
+
        if(handle->to_be_written == NULL) {
                handle->to_be_written = g_byte_array_new();
        }
        handle->to_be_written = g_byte_array_append(handle->to_be_written, buffer, num_bytes);
-       *bytes_read = num_bytes;
+       *bytes_written = num_bytes;
        
        DEBUG_HTTP (("-Write (0)"));
        
@@ -1880,10 +1889,50 @@ do_read (GnomeVFSMethod *method,
        if (handle->file_info->flags & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
                GnomeVFSFileSize max_bytes;
 
-               max_bytes = handle->file_info->size - handle->bytes_read;
+               max_bytes = MAX (0, handle->file_info->size - handle->offset);
                num_bytes = MIN (max_bytes, num_bytes);
        }
 
+       if (!num_bytes) {
+               *bytes_read = 0;
+               return GNOME_VFS_OK;
+       }
+
+       if (1
+           && handle->offset >  handle->socket_buffer_offset
+           && handle->offset <= handle->socket_buffer_offset+MAX_BUFFER_SEEK_SKIP_READ) {
+static char drop_buffer[0x1000];
+GnomeVFSFileSize bytes, bytes_read;
+GnomeVFSResult result;
+
+               while ((bytes=MIN(sizeof(drop_buffer), handle->offset - handle->socket_buffer_offset))) {
+                       result = gnome_vfs_socket_buffer_read (handle->socket_buffer, drop_buffer, 
+                                       bytes, &bytes_read);
+                       if (result != GNOME_VFS_OK)
+                               return result;
+                       handle->socket_buffer_offset += bytes_read;
+               }
+       }
+
+       if (handle->offset != handle->socket_buffer_offset) {
+               GnomeVFSURI *uri = handle->uri;
+               gchar *extra_headers;
+
+               gnome_vfs_uri_ref(uri);
+               http_handle_close (handle, context);
+               extra_headers = g_strdup_printf("Range: bytes=%" G_GINT64_FORMAT "-\r\n",(gint64)handle->offset);
+               result = make_request (handle, uri, "GET", NULL, extra_headers,
+                                      context);
+               g_free (extra_headers);
+               gnome_vfs_uri_unref(uri);
+               if (result != GNOME_VFS_OK) {
+                       /* FIXME: 'method_handle' is now broken! */
+                       memset(handle, 0, sizeof (*handle));
+                       return result;
+               }
+               handle->socket_buffer_offset = handle->offset;
+       }
+
        result = gnome_vfs_socket_buffer_read (handle->socket_buffer, buffer, 
                        num_bytes, bytes_read);
        
@@ -1891,7 +1940,8 @@ do_read (GnomeVFSMethod *method,
                return GNOME_VFS_ERROR_EOF;
        }                                      
 
-       handle->bytes_read += *bytes_read;
+       handle->socket_buffer_offset += *bytes_read;
+       handle->offset += *bytes_read;
 
        DEBUG_HTTP (("-Read (%d)", result));
        ANALYZE_HTTP ("==> -do_read");
@@ -1899,6 +1949,53 @@ do_read (GnomeVFSMethod *method,
        return result;
 }
 
+static GnomeVFSResult
+do_seek (GnomeVFSMethod *method,
+        GnomeVFSMethodHandle *method_handle,
+        GnomeVFSSeekPosition  whence,
+        GnomeVFSFileOffset    offset,
+        GnomeVFSContext *context)
+{
+       HttpFileHandle *handle;
+
+       handle = (HttpFileHandle *) method_handle;
+
+       if (handle->to_be_written != NULL)
+               return GNOME_VFS_ERROR_NOT_SUPPORTED;
+
+       switch (whence) {
+       case GNOME_VFS_SEEK_START:
+               handle->offset = offset;
+               break;
+       case GNOME_VFS_SEEK_CURRENT:
+               handle->offset += offset;
+               break;
+       case GNOME_VFS_SEEK_END:
+               if (!(handle->file_info->flags & GNOME_VFS_FILE_INFO_FIELDS_SIZE))
+                       return GNOME_VFS_ERROR_NOT_SUPPORTED;
+               handle->offset = handle->file_info->size + offset;
+               break;
+       default:
+               g_return_val_if_reached(GNOME_VFS_ERROR_NOT_SUPPORTED);
+       }
+
+       return GNOME_VFS_OK;
+}
+
+static GnomeVFSResult
+do_tell (GnomeVFSMethod *method,
+        GnomeVFSMethodHandle *method_handle,
+        GnomeVFSFileOffset *offset_return)
+{
+       HttpFileHandle *handle;
+
+       handle = (HttpFileHandle *) method_handle;
+
+       *offset_return = handle->offset;
+
+       return GNOME_VFS_OK;
+}
+
 /* Directory handling - WebDAV servers only */
 
 static void
@@ -2788,8 +2885,8 @@ static GnomeVFSMethod method = {
        do_close,
        do_read,
        do_write,
-       NULL, /* seek */
-       NULL, /* tell */
+       do_seek,
+       do_tell,
        NULL, /* truncate_handle */
        do_open_directory,
        do_close_directory,