/* 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"
/* 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;
return ret;
}
-static HttpFileHandle *
-http_file_handle_new (GnomeVFSSocketBuffer *socket_buffer,
+/* Does not allocate the 'handle' memory. */
+static void
+http_file_handle_new (HttpFileHandle *handle,
+ GnomeVFSSocketBuffer *socket_buffer,
GnomeVFSURI *uri)
{
- HttpFileHandle *result;
-
- result = g_new0 (HttpFileHandle, 1);
+ memset (handle, 0, sizeof (*handle));
- result->socket_buffer = socket_buffer;
- result->uri_string = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE );
- result->uri = uri;
- gnome_vfs_uri_ref(result->uri);
+ handle->socket_buffer = socket_buffer;
+ handle->uri_string = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE );
+ handle->uri = uri;
+ gnome_vfs_uri_ref(handle->uri);
- result->file_info = defaults_file_info_new();
- result->file_info->name = gnome_vfs_uri_extract_short_name (uri);
-
- return result;
+ handle->file_info = defaults_file_info_new();
+ handle->file_info->name = gnome_vfs_uri_extract_short_name (uri);
}
+/* Does not free the 'handle' memory. */
static void
http_file_handle_destroy (HttpFileHandle *handle)
{
g_list_foreach(handle->files, (GFunc)gnome_vfs_file_info_unref, NULL);
g_list_free(handle->files);
-
- g_free (handle);
}
/* The following comes from GNU Wget with minor changes by myself.
create_handle (GnomeVFSURI *uri,
GnomeVFSSocketBuffer *socket_buffer,
GnomeVFSContext *context,
- /* OUT */ HttpFileHandle **p_handle)
+ /* OUT */ HttpFileHandle *handle)
{
GString *header_string;
GnomeVFSResult result;
guint server_status;
- g_return_val_if_fail (p_handle != NULL, GNOME_VFS_ERROR_INTERNAL);
+ g_return_val_if_fail (handle != NULL, GNOME_VFS_ERROR_INTERNAL);
- *p_handle = http_file_handle_new (socket_buffer, uri);
+ http_file_handle_new (handle, socket_buffer, uri);
header_string = g_string_new (NULL);
goto error;
}
- (*p_handle)->server_status = server_status;
+ handle->server_status = server_status;
ANALYZE_HTTP ("==> +create_handle: fetching headers");
break;
}
- (*p_handle)->response_headers = g_list_prepend ((*p_handle)->response_headers,
+ handle->response_headers = g_list_prepend (handle->response_headers,
g_strdup (header_string->str));
/* We don't really care if we successfully parse the
* past we would return NOT_FOUND if any header could
* not be parsed, but that seems wrong.
*/
- parse_header (*p_handle, header_string->str);
+ parse_header (handle, header_string->str);
}
- invoke_callback_headers_received (*p_handle);
+ invoke_callback_headers_received (handle);
ANALYZE_HTTP ("==> -create_handle: fetching headers");
}
static GnomeVFSResult
-make_request (HttpFileHandle **handle_return,
+make_request (HttpFileHandle *handle,
GnomeVFSURI *uri,
const gchar *method,
GByteArray *data,
char *authn_header_request;
char *authn_header_proxy;
- g_return_val_if_fail (handle_return != NULL, GNOME_VFS_ERROR_INTERNAL);
- *handle_return = NULL;
+ g_return_val_if_fail (handle != NULL, GNOME_VFS_ERROR_INTERNAL);
ANALYZE_HTTP ("==> +make_request");
}
/* Read the headers and create our internal HTTP file handle. */
- result = create_handle (uri, socket_buffer, context, handle_return);
+ result = create_handle (uri, socket_buffer, context, handle);
if (result == GNOME_VFS_OK) {
socket_buffer = NULL;
break;
}
- if ((*handle_return)->server_status == HTTP_STATUS_UNAUTHORIZED) {
- if (! check_authn_retry_request (*handle_return, AuthnHeader_WWW, authn_header_request)) {
+ if (handle->server_status == HTTP_STATUS_UNAUTHORIZED) {
+ if (! check_authn_retry_request (handle, AuthnHeader_WWW, authn_header_request)) {
break;
}
- } else if ((*handle_return)->server_status == HTTP_STATUS_PROXY_AUTH_REQUIRED) {
- if (! check_authn_retry_request (*handle_return, AuthnHeader_WWW, authn_header_proxy)) {
+ } else if (handle->server_status == HTTP_STATUS_PROXY_AUTH_REQUIRED) {
+ if (! check_authn_retry_request (handle, AuthnHeader_WWW, authn_header_proxy)) {
break;
}
} else {
break;
}
- http_file_handle_destroy (*handle_return);
- *handle_return = NULL;
+ http_file_handle_destroy (handle);
+ handle = NULL;
}
g_free (authn_header_request);
g_free (authn_header_proxy);
- if (result != GNOME_VFS_OK && *handle_return != NULL) {
- http_file_handle_destroy (*handle_return);
- *handle_return = NULL;
+ if (result != GNOME_VFS_OK && handle != NULL) {
+ http_file_handle_destroy (handle);
+ handle = NULL;
}
if (request != NULL) {
ANALYZE_HTTP ("==> +do_open");
DEBUG_HTTP (("+Open URI: '%s' mode:'%c'", gnome_vfs_uri_to_string(uri, 0),
mode & GNOME_VFS_OPEN_READ ? 'R' : 'W'));
-
+
+ handle = g_new (HttpFileHandle, 1);
if (mode & GNOME_VFS_OPEN_READ) {
- result = make_request (&handle, uri, "GET", NULL, NULL,
+ result = make_request (handle, uri, "GET", NULL, NULL,
context);
} else {
- handle = http_file_handle_new(NULL, uri); /* shrug */
+ http_file_handle_new(handle, NULL, uri); /* shrug */
}
if (result == GNOME_VFS_OK) {
*method_handle = (GnomeVFSMethodHandle *) handle;
ANALYZE_HTTP ("==> Checking to see if file exists");
- result = make_request (&handle, uri, "HEAD", NULL, NULL,
+ handle = g_new (HttpFileHandle, 1);
+ result = make_request (handle, uri, "HEAD", NULL, NULL,
context);
http_handle_close (handle, context);
+ g_free (handle);
if (result != GNOME_VFS_OK &&
result != GNOME_VFS_ERROR_NOT_FOUND) {
ANALYZE_HTTP ("==> Creating initial file");
- result = make_request (&handle, uri, "PUT", bytes, NULL, context);
+ handle = g_new (HttpFileHandle, 1);
+ result = make_request (handle, uri, "PUT", bytes, NULL, context);
http_handle_close(handle, context);
+ g_free (handle);
if (result != GNOME_VFS_OK) {
/* the PUT failed */
http_cache_invalidate_uri (uri);
ANALYZE_HTTP ("==> doing PUT");
- result = make_request (&new_handle, uri, "PUT", bytes,
+ new_handle = g_new (HttpFileHandle, 1);
+ result = make_request (new_handle, uri, "PUT", bytes,
extraheader, context);
g_free (extraheader);
http_handle_close (new_handle, context);
+ g_free (new_handle);
} else {
result = GNOME_VFS_OK;
}
-
+
http_handle_close (old_handle, context);
+ g_free (old_handle);
DEBUG_HTTP (("-Close (%d)", result));
ANALYZE_HTTP ("==> -do_close");
GnomeVFSMethodHandle *method_handle,
gconstpointer buffer,
GnomeVFSFileSize num_bytes,
- GnomeVFSFileSize *bytes_read,
+ GnomeVFSFileSize *bytes_written,
GnomeVFSContext *context)
{
HttpFileHandle *handle;
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)"));
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);
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");
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
static GnomeVFSResult
-make_propfind_request (HttpFileHandle **handle_return,
+make_propfind_request (HttpFileHandle *handle,
GnomeVFSURI *uri,
gint depth,
GnomeVFSContext *context)
http_cache_invalidate_uri_and_children (uri);
}
- result = make_request (handle_return, uri, "PROPFIND", request,
+ result = make_request (handle, uri, "PROPFIND", request,
extraheaders, context);
/* FIXME bugzilla.gnome.org 43834: It looks like some http
* redirects or any other legal response. This case probably
* needs to be made more robust.
*/
- if (result == GNOME_VFS_OK && (*handle_return)->server_status != 207) { /* Multi-Status */
- DEBUG_HTTP (("HTTP server returned an invalid PROPFIND response: %d", (*handle_return)->server_status));
+ if (result == GNOME_VFS_OK && handle->server_status != 207) { /* Multi-Status */
+ DEBUG_HTTP (("HTTP server returned an invalid PROPFIND response: %d", handle->server_status));
result = GNOME_VFS_ERROR_NOT_SUPPORTED;
}
if (result == GNOME_VFS_OK) {
do {
- result = do_read (NULL, (GnomeVFSMethodHandle *) *handle_return,
+ result = do_read (NULL, (GnomeVFSMethodHandle *) handle,
buffer, num_bytes, &bytes_read, context);
if (result != GNOME_VFS_OK ) {
process_propfind_response (cur->xmlChildrenNode, uri);
if (file_info->name != NULL) {
- (*handle_return)->files = g_list_append ((*handle_return)->files, file_info);
+ handle->files = g_list_append (handle->files, file_info);
} else {
/* This response refers to the root node */
/* Abandon the old information that came from create_handle*/
- file_info->name = (*handle_return)->file_info->name;
- (*handle_return)->file_info->name = NULL;
- gnome_vfs_file_info_unref ((*handle_return)->file_info);
- (*handle_return)->file_info = file_info;
+ file_info->name = handle->file_info->name;
+ handle->file_info->name = NULL;
+ gnome_vfs_file_info_unref (handle->file_info);
+ handle->file_info = file_info;
found_root_node_props = TRUE;
}
*/
if (depth == 0) {
- http_cache_add_uri (uri, (*handle_return)->file_info, TRUE);
+ http_cache_add_uri (uri, handle->file_info, TRUE);
} else {
- http_cache_add_uri_and_children (uri, (*handle_return)->file_info, (*handle_return)->files);
+ http_cache_add_uri_and_children (uri, handle->file_info, handle->files);
}
cleanup:
xmlFreeParserCtxt(parserContext);
if (result != GNOME_VFS_OK) {
- http_handle_close (*handle_return, context);
- *handle_return = NULL;
+ http_handle_close (handle, context);
+ g_free (handle);
}
ANALYZE_HTTP ("==> -make_propfind_request");
file_info_cached = http_cache_check_directory_uri (uri, &child_file_info_cached_list);
if (file_info_cached) {
- handle = http_file_handle_new (NULL, uri);
+ handle = g_new (HttpFileHandle, 1);
+ http_file_handle_new (handle, NULL, uri);
gnome_vfs_file_info_unref (handle->file_info);
handle->file_info = file_info_cached;
handle->files = child_file_info_cached_list;
result = GNOME_VFS_OK;
} else {
- result = make_propfind_request(&handle, uri, 1, context);
+ handle = g_new (HttpFileHandle, 1);
+ result = make_propfind_request(handle, uri, 1, context);
/* mfleming -- is this necessary? Most DAV server's I've seen don't have the horrible
* lack-of-trailing-/-is-a-301 problem for PROPFIND's
*/
&& handle->file_info->type != GNOME_VFS_FILE_TYPE_DIRECTORY) {
result = GNOME_VFS_ERROR_NOT_A_DIRECTORY;
http_handle_close (handle, context);
+ g_free (handle);
handle = NULL;
}
}
handle = (HttpFileHandle *) method_handle;
http_handle_close(handle, context);
+ g_free (handle);
DEBUG_HTTP (("-Close_Directory (0) handle:0x%08x", (unsigned int) method_handle));
* Start off by making a PROPFIND request. Fall back to a HEAD if it fails
*/
- result = make_propfind_request (&handle, uri, 0, context);
+ handle = g_new (HttpFileHandle, 1);
+ result = make_propfind_request (handle, uri, 0, context);
/* Note that theoretically we could not bother with this request if we get a 404 back,
* but since some servers seem to return wierd things on PROPFIND (mostly 200 OK's...)
if (result == GNOME_VFS_OK) {
gnome_vfs_file_info_copy (file_info, handle->file_info);
http_handle_close (handle, context);
+ g_free (handle);
handle = NULL;
} else {
g_assert (handle == NULL); /* Make sure we're not leaking some old one */
ANALYZE_HTTP ("==> do_get_file_info: do GET ");
- result = make_request (&handle, uri, "GET", NULL, NULL, context);
+ handle = g_new (HttpFileHandle, 1);
+ result = make_request (handle, uri, "GET", NULL, NULL, context);
if (result == GNOME_VFS_OK) {
gnome_vfs_file_info_copy (file_info, handle->file_info);
http_cache_add_uri (uri, handle->file_info, FALSE);
http_handle_close (handle, context);
+ g_free (handle);
}
/* If we get a redirect, we should be
* So we do a PROPFIND first to find out
*/
/* FIXME check cache here */
- result = make_propfind_request(&handle, uri, 0, context);
+ handle = g_new (HttpFileHandle, 1);
+ result = make_propfind_request(handle, uri, 0, context);
if (result == GNOME_VFS_OK) {
result = GNOME_VFS_ERROR_FILE_EXISTS;
if (result == GNOME_VFS_ERROR_NOT_FOUND) {
http_cache_invalidate_uri_parent (uri);
- result = make_request (&handle, uri, "MKCOL", NULL, NULL, context);
+ handle = g_new (HttpFileHandle, 1);
+ result = make_request (handle, uri, "MKCOL", NULL, NULL, context);
}
}
http_handle_close (handle, context);
+ g_free (handle);
if (result == GNOME_VFS_ERROR_NOT_FOUND) {
result = resolve_409 (method, uri, context);
/* FIXME this should return GNOME_VFS_ERROR_DIRECTORY_NOT_EMPTY if the
* directory is not empty
*/
- result = make_request (&handle, uri, "DELETE", NULL, NULL,
+ handle = g_new (HttpFileHandle, 1);
+ result = make_request (handle, uri, "DELETE", NULL, NULL,
context);
http_handle_close (handle, context);
+ g_free (handle);
DEBUG_HTTP (("-Remove_Directory (%d)", result));
ANALYZE_HTTP ("==> -do_remove_directory");
destpath = gnome_vfs_uri_to_string (new_uri, GNOME_VFS_URI_HIDE_USER_NAME|GNOME_VFS_URI_HIDE_PASSWORD);
destheader = g_strdup_printf ("Destination: %s\r\nOverwrite: %c\r\n", destpath, force_replace ? 'T' : 'F' );
- result = make_request (&handle, old_uri, "MOVE", NULL, destheader, context);
+ handle = g_new (HttpFileHandle, 1);
+ result = make_request (handle, old_uri, "MOVE", NULL, destheader, context);
http_handle_close (handle, context);
+ g_free (handle);
handle = NULL;
if (result == GNOME_VFS_ERROR_NOT_FOUND) {
do_close,
do_read,
do_write,
- NULL, /* seek */
- NULL, /* tell */
+ do_seek,
+ do_tell,
NULL, /* truncate_handle */
do_open_directory,
do_close_directory,