gvfs r1368 - in trunk: . daemon
- From: gicmo svn gnome org
- To: svn-commits-list gnome org
- Subject: gvfs r1368 - in trunk: . daemon
- Date: Mon, 25 Feb 2008 14:55:01 +0000 (GMT)
Author: gicmo
Date: Mon Feb 25 14:55:01 2008
New Revision: 1368
URL: http://svn.gnome.org/viewvc/gvfs?rev=1368&view=rev
Log:
2008-02-25 Christian Kellner <gicmo gnome org>
* daemon/gvfsbackenddav.c:
- Port the mount operation to use the sync i/op.
- Keep the auth information around so we can use them again in
the case that a subpath requires different authentication. This
is needed since libsoup will forgot all auth after a 401.
- Ignore trailing slashes in ms_response_is_target ().
- Add an initial version of make_directory ().
* daemon/gvfsbackendhttp.c:
* daemon/gvfsbackendhttp.h:
Add message_new_from_filename_full which will add a trailing "/"
if is_dir is true. (Saves uneccesary redirects in some cases)
Various bits and pieces came from Yann Rouillard.
Modified:
trunk/ChangeLog
trunk/daemon/gvfsbackenddav.c
trunk/daemon/gvfsbackendhttp.c
trunk/daemon/gvfsbackendhttp.h
Modified: trunk/daemon/gvfsbackenddav.c
==============================================================================
--- trunk/daemon/gvfsbackenddav.c (original)
+++ trunk/daemon/gvfsbackenddav.c Mon Feb 25 14:55:01 2008
@@ -60,10 +60,33 @@
#include "soup-input-stream.h"
#include "soup-output-stream.h"
+typedef struct _MountAuthInfo MountAuthInfo;
+
+static void mount_auth_info_free (MountAuthInfo *info);
+
+struct _MountAuthInfo {
+
+ SoupSession *session;
+ GMountSource *mount_source;
+
+ /* for server authentication */
+ char *username;
+ char *password;
+ char *last_realm;
+
+ /* for proxy authentication */
+ char *proxy_user;
+ char *proxy_password;
+
+};
+
+
+
struct _GVfsBackendDav
{
GVfsBackendHttp parent_instance;
+ MountAuthInfo auth_info;
};
G_DEFINE_TYPE (GVfsBackendDav, g_vfs_backend_dav, G_VFS_TYPE_BACKEND_HTTP)
@@ -71,6 +94,12 @@
static void
g_vfs_backend_dav_finalize (GObject *object)
{
+ GVfsBackendDav *dav_backend;
+
+ dav_backend = G_VFS_BACKEND_DAV (object);
+
+ mount_auth_info_free (&(dav_backend->auth_info));
+
if (G_OBJECT_CLASS (g_vfs_backend_dav_parent_class)->finalize)
(*G_OBJECT_CLASS (g_vfs_backend_dav_parent_class)->finalize) (object);
}
@@ -104,25 +133,25 @@
static char *
path_get_parent_dir (const char *path)
{
- char *parent;
- size_t len;
+ char *parent;
+ size_t len;
- if ((len = strlen (path)) < 1)
- return NULL;
+ if ((len = strlen (path)) < 1)
+ return NULL;
- /* maybe this should be while, but then again
- * I should be reading the uri rfc and see
- * what the deal was with multiple slashes */
+ /* maybe this should be while, but then again
+ * I should be reading the uri rfc and see
+ * what the deal was with multiple slashes */
- if (path[len - 1] == '/')
- len--;
+ if (path[len - 1] == '/')
+ len--;
- parent = g_strrstr_len (path, len, "/");
+ parent = g_strrstr_len (path, len, "/");
- if (parent == NULL)
- return NULL;
+ if (parent == NULL)
+ return NULL;
- return g_strndup (path, (parent - path) + 1);
+ return g_strndup (path, (parent - path) + 1);
}
/* ************************************************************************* */
@@ -419,11 +448,11 @@
SoupURI *uri;
gboolean res;
- res = FALSE;
- uri = NULL;
- path = NULL;
+ res = FALSE;
+ uri = NULL;
+ path = NULL;
target = response->multistatus->target;
- text = node_get_content (response->href);
+ text = node_get_content (response->href);
if (text == NULL)
return FALSE;
@@ -439,7 +468,21 @@
}
if (path)
- res = g_str_equal (path, target->path);
+ {
+ size_t len_path, len_target;
+
+ len_path = strlen (path);
+ len_target = strlen (target->path);
+
+ while (path[len_path - 1] == '/')
+ len_path--;
+
+ while (path[len_target - 1] == '/')
+ len_target--;
+
+ if (len_path == len_target)
+ res = ! g_ascii_strncasecmp (path, target->path, len_path);
+ }
if (uri)
soup_uri_free (uri);
@@ -551,6 +594,8 @@
xmlNodePtr node;
guint status;
char *basename;
+ const char *text;
+ GTimeVal tv;
basename = ms_response_get_basename (response);
g_file_info_set_name (info, basename);
@@ -558,7 +603,6 @@
g_free (basename);
ms_response_get_propstat_iter (response, &iter);
-
while (xml_node_iter_next (&iter))
{
status = ms_response_get_propstat (&iter, &propstat);
@@ -568,9 +612,6 @@
for (node = propstat.prop_node->children; node; node = node->next)
{
- const char *text;
- GTimeVal tv;
-
if (! node_is_element (node))
continue; /* FIXME: check namespace, parse user data nodes*/
@@ -598,10 +639,6 @@
g_file_info_set_attribute_uint64 (info,
G_FILE_ATTRIBUTE_TIME_CREATED,
tv.tv_sec);
-
- g_file_info_set_attribute_uint64 (info,
- G_FILE_ATTRIBUTE_TIME_CREATED_USEC,
- tv.tv_usec);
}
else if (node_has_name (node, "getcontenttype"))
{
@@ -659,82 +696,102 @@
return file_type;
}
-static char *
-create_propfind_request (GFileAttributeMatcher *matcher, gulong *size)
-{
- xmlOutputBufferPtr buf;
- xmlNodePtr node;
- xmlNodePtr root;
- xmlDocPtr doc;
- xmlNsPtr nsdav;
- char *res;
+#define PROPSTAT_XML_BEGIN \
+ "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" \
+ " <D:propfind xmlns:D=\"DAV:\">\n"
+
+#define PROPSTAT_XML_ALLPROP " <D:allprop/>\n"
+#define PROPSTAT_XML_PROP_BEGIN " <D:prop>\n"
+#define PROPSTAT_XML_PROP_END " </D:prop>\n"
- doc = xmlNewDoc ((xmlChar *) "1.0");
- root = xmlNewNode (NULL, (xmlChar *) "propfind");
- nsdav = xmlNewNs (root, (xmlChar *) "DAV:", (xmlChar *) "D");
- xmlSetNs (root, nsdav);
+#define PROPSTAT_XML_END \
+ " </D:propfind>"
- node = xmlNewTextChild (root, nsdav, (xmlChar *) "prop", NULL);
+typedef struct _PropName {
+
+ const char *name;
+ const char *namespace;
+} PropName;
+static SoupMessage *
+propfind_request_new (GVfsBackend *backend,
+ const char *filename,
+ guint depth,
+ const PropName *properties)
+{
+ SoupMessage *msg;
+ const char *header_depth;
+ GString *body;
+ msg = message_new_from_filename_full (backend, SOUP_METHOD_PROPFIND,
+ filename, (depth > 0));
- /* FIXME: we should just ask for properties that
- * the matcher tells us to ask for
- * nota bene: <D:reftarget/> */
- xmlNewTextChild (node, nsdav, (xmlChar *) "resourcetype", NULL);
- xmlNewTextChild (node, nsdav, (xmlChar *) "displayname", NULL);
- xmlNewTextChild (node, nsdav, (xmlChar *) "getetag", NULL);
- xmlNewTextChild (node, nsdav, (xmlChar *) "getlastmodified", NULL);
- xmlNewTextChild (node, nsdav, (xmlChar *) "creationdate", NULL);
- xmlNewTextChild (node, nsdav, (xmlChar *) "getcontenttype", NULL);
- xmlNewTextChild (node, nsdav, (xmlChar *) "getcontentlength", NULL);
+ if (msg == NULL)
+ return NULL;
- buf = xmlAllocOutputBuffer (NULL);
- xmlNodeDumpOutput (buf, doc, root, 0, 1, NULL);
- xmlOutputBufferFlush (buf);
+ if (depth == 0)
+ header_depth = "0";
+ else if (depth == 1)
+ header_depth = "1";
+ else
+ header_depth = "infinity";
- res = g_strndup ((char *) buf->buffer->content, buf->buffer->use);
- *size = buf->buffer->use;
+ soup_message_headers_append (msg->request_headers, "Depth", header_depth);
- xmlOutputBufferClose (buf);
- xmlFreeDoc (doc);
- return res;
-}
+ body = g_string_new (PROPSTAT_XML_BEGIN);
+ if (properties != NULL)
+ {
+ const PropName *prop;
-/* ************************************************************************* */
-/* */
+ for (prop = properties; prop->name; prop++)
+ {
+ if (prop->namespace != NULL)
+ g_string_append (body, "<%s xmlns=\"%s\"/>");
+ else
+ g_string_append (body, "<D:%s/>");
+ }
+ }
+ else
+ g_string_append (body, PROPSTAT_XML_ALLPROP);
+
-typedef struct _MountOpData {
+ g_string_append (body, PROPSTAT_XML_END);
- gulong signal_id;
+ soup_message_set_request (msg, "application/xml",
+ SOUP_MEMORY_TAKE,
+ body->str,
+ body->len);
- SoupSession *session;
- GMountSource *mount_source;
+ g_string_free (body, FALSE);
- char *last_good_path;
+ return msg;
+}
- /* for server authentication */
- char *username;
- char *password;
- char *last_realm;
+static void
+message_add_apply_to_redirect_header (SoupMessage *msg,
+ GFileQueryInfoFlags flags)
+{
+ const char *header_redirect;
+
+ /* RFC 4437 */
+ if (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS)
+ header_redirect = "F";
+ else
+ header_redirect = "T";
+
+ soup_message_headers_append (msg->request_headers,
+ "Apply-To-Redirect-Ref", header_redirect);
+}
+/* ************************************************************************* */
+/* */
- /* for proxy authentication */
- char *proxy_user;
- char *proxy_password;
-} MountOpData;
static void
-mount_op_data_free (gpointer _data)
+mount_auth_info_free (MountAuthInfo *data)
{
- MountOpData *data;
-
- data = (MountOpData *) _data;
-
- g_free (data->last_good_path);
-
if (data->mount_source)
g_object_unref (data->mount_source);
@@ -744,28 +801,52 @@
g_free (data->proxy_user);
g_free (data->proxy_password);
- g_free (data);
}
static void
-soup_authenticate (SoupSession *session,
- SoupMessage *msg,
- SoupAuth *auth,
- gboolean retrying,
- gpointer user_data)
-{
- MountOpData *data;
- const char *username;
- const char *password;
- gboolean res;
- gboolean aborted;
- char *new_username;
- char *new_password;
- char *prompt;
+soup_authenticate_from_data (SoupSession *session,
+ SoupMessage *msg,
+ SoupAuth *auth,
+ gboolean retrying,
+ gpointer user_data)
+{
+ MountAuthInfo *data;
+
+ g_print ("+ soup_authenticate_from_data (%s) \n",
+ retrying ? "retrying" : "first auth");
+
+ data = (MountAuthInfo *) user_data;
- g_print ("+ soup_authenticate \n");
+ if (retrying)
+ return;
- data = (MountOpData *) user_data;
+ if (soup_auth_is_for_proxy (auth))
+ soup_auth_authenticate (auth, data->proxy_user, data->proxy_password);
+ else
+ soup_auth_authenticate (auth, data->username, data->password);
+
+}
+
+static void
+soup_authenticate_interactive (SoupSession *session,
+ SoupMessage *msg,
+ SoupAuth *auth,
+ gboolean retrying,
+ gpointer user_data)
+{
+ MountAuthInfo *data;
+ const char *username;
+ const char *password;
+ gboolean res;
+ gboolean aborted;
+ char *new_username;
+ char *new_password;
+ char *prompt;
+
+ g_print ("+ soup_authenticate_interactive (%s) \n",
+ retrying ? "retrying" : "first auth");
+
+ data = (MountAuthInfo *) user_data;
new_username = NULL;
new_password = NULL;
@@ -803,8 +884,6 @@
prompt = g_strdup_printf (_("Enter password for %s"), auth_realm);
}
- soup_session_pause_message (data->session, msg);
-
res = g_mount_source_ask_password (data->mount_source,
prompt,
username,
@@ -816,117 +895,77 @@
&new_username,
NULL,
NULL);
- if (res && !aborted)
+
+ if (res && !aborted) {
+
soup_auth_authenticate (auth, new_username, new_password);
- g_free (new_password);
- g_free (new_username);
+ if (soup_auth_is_for_proxy (auth))
+ {
+ g_free (data->proxy_user);
+ g_free (data->proxy_password);
+ data->proxy_password = new_password;
+ data->proxy_user = new_username;
+ }
+ else
+ {
+ g_free (data->username);
+ g_free (data->password);
+
+ data->username = new_username;
+ data->password = new_password;
+ }
+ }
g_print ("- soup_authenticate \n");
g_free (prompt);
}
-static void
-discover_mount_root_ready (SoupSession *session,
- SoupMessage *msg,
- gpointer user_data)
-{
- GVfsBackendDav *backend;
- GVfsJobMount *job;
- MountOpData *data;
- GMountSpec *mount_spec;
- SoupURI *mount_base;
- gboolean is_success;
- gboolean is_dav;
-
- job = G_VFS_JOB_MOUNT (user_data);
- backend = G_VFS_BACKEND_DAV (job->backend);
- mount_base = G_VFS_BACKEND_HTTP (backend)->mount_base;
- data = (MountOpData *) G_VFS_JOB (job)->backend_data;
-
- is_success = SOUP_STATUS_IS_SUCCESSFUL (msg->status_code);
- is_dav = sm_has_header (msg, "DAV");
-
- g_print ("+ discover_mount_root_ready \n");
-
- if (is_success && is_dav)
- {
+static inline GMountSpec *
+g_mount_spec_dup_known (GMountSpec *spec)
+{
+ static const char *known_keys[] = {"host", "user", "port", "ssl", NULL};
+ GMountSpec *new_spec;
+ const char **iter;
+ const char *value;
+ const char *type;
- data->last_good_path = mount_base->path;
- mount_base->path = path_get_parent_dir (mount_base->path);
+ type = g_mount_spec_get_type (spec);
+ new_spec = g_mount_spec_new (type);
- if (mount_base->path)
- {
- SoupMessage *message;
- message = message_new_from_uri (SOUP_METHOD_OPTIONS, mount_base);
- soup_session_queue_message (session, message,
- discover_mount_root_ready, job);
- return;
- }
- }
-
- /* we have reached the end of paths we are allowed to
- * chdir up to (or couldn't chdir up at all) */
-
- /* check if we at all have a good path */
- if (data->last_good_path == NULL)
+ for (iter = known_keys; *iter; iter++)
{
- if (!is_success)
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR,G_IO_ERROR_FAILED,
- _("HTTP Error: %s"), msg->reason_phrase);
- else
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR,G_IO_ERROR_FAILED,
- _("Not a WebDAV enabled share"));
+ value = g_mount_spec_get (spec, *iter);
- return;
+ if (value)
+ g_mount_spec_set (new_spec, *iter, value);
}
- g_free (mount_base->path);
- mount_base->path = data->last_good_path;
- data->last_good_path = NULL;
- mount_spec = g_mount_spec_new ("dav");
-
- g_mount_spec_set (mount_spec, "host", mount_base->host);
-
- if (mount_base->user)
- g_mount_spec_set (mount_spec, "user", mount_base->user);
-
- if (mount_base->scheme == SOUP_URI_SCHEME_HTTP)
- g_mount_spec_set (mount_spec, "ssl", "false");
- else if (mount_base->scheme == SOUP_URI_SCHEME_HTTPS)
- g_mount_spec_set (mount_spec, "ssl", "true");
-
- g_mount_spec_set_mount_prefix (mount_spec, mount_base->path);
- g_vfs_backend_set_icon_name (G_VFS_BACKEND (backend), "folder-remote");
-
- g_vfs_backend_set_mount_spec (G_VFS_BACKEND (backend), mount_spec);
- g_mount_spec_unref (mount_spec);
-
- g_signal_handler_disconnect (session, data->signal_id);
-
- g_print ("- discover_mount_root_ready success: %s \n", mount_base->path);
- g_vfs_job_succeeded (G_VFS_JOB (job));
+ return new_spec;
}
-static gboolean
-try_mount (GVfsBackend *backend,
- GVfsJobMount *job,
- GMountSpec *mount_spec,
- GMountSource *mount_source,
- gboolean is_automount)
+static void
+do_mount (GVfsBackend *backend,
+ GVfsJobMount *job,
+ GMountSpec *mount_spec,
+ GMountSource *mount_source,
+ gboolean is_automount)
{
- MountOpData *data;
+ MountAuthInfo *info;
SoupSession *session;
SoupMessage *msg;
- SoupURI *uri;
+ SoupURI *mount_base;
const char *host;
const char *user;
const char *port;
const char *ssl;
guint port_num;
+ gulong signal_id;
+ guint status;
+ gboolean is_success;
+ gboolean is_dav;
+ char *last_good_path;
g_print ("+ mount\n");
@@ -941,63 +980,135 @@
G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
_("Invalid mount spec"));
- return TRUE;
+ return;
}
- uri = soup_uri_new (NULL);
+ mount_base = soup_uri_new (NULL);
if (ssl != NULL && (strcmp (ssl, "true") == 0))
- soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTPS);
+ soup_uri_set_scheme (mount_base, SOUP_URI_SCHEME_HTTPS);
else
- soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTP);
+ soup_uri_set_scheme (mount_base, SOUP_URI_SCHEME_HTTP);
- soup_uri_set_user (uri, user);
+ soup_uri_set_user (mount_base, user);
if (port && (port_num = atoi (port)))
- soup_uri_set_port (uri, port_num);
+ soup_uri_set_port (mount_base, port_num);
- soup_uri_set_host (uri, host);
- soup_uri_set_path (uri, mount_spec->mount_prefix);
+ soup_uri_set_host (mount_base, host);
+ soup_uri_set_path (mount_base, mount_spec->mount_prefix);
session = G_VFS_BACKEND_HTTP (backend)->session;
- G_VFS_BACKEND_HTTP (backend)->mount_base = uri;
+ G_VFS_BACKEND_HTTP (backend)->mount_base = mount_base;
+
+ info = &(G_VFS_BACKEND_DAV (backend)->auth_info);
+ info->mount_source = g_object_ref (mount_source);
+ info->username = g_strdup (user);
+
+ signal_id = g_signal_connect (session, "authenticate",
+ G_CALLBACK (soup_authenticate_interactive),
+ info);
+
+ last_good_path = NULL;
+ msg = message_new_from_uri (SOUP_METHOD_OPTIONS, mount_base);
+
+ do {
+ status = soup_session_send_message (session, msg);
+
+ is_success = SOUP_STATUS_IS_SUCCESSFUL (status);
+ is_dav = sm_has_header (msg, "DAV");
- msg = message_new_from_uri (SOUP_METHOD_OPTIONS, uri);
- soup_session_queue_message (session, msg, discover_mount_root_ready, job);
+ soup_message_headers_clear (msg->response_headers);
+ soup_message_body_truncate (msg->response_body);
- data = g_new0 (MountOpData, 1);
- data->session = g_object_ref (session);
- data->mount_source = g_object_ref (mount_source);
- data->username = g_strdup (user);
+ if (is_success && is_dav)
+ {
+ g_free (last_good_path);
+ last_good_path = mount_base->path;
+ mount_base->path = path_get_parent_dir (mount_base->path);
+ soup_message_set_uri (msg, mount_base);
+ }
+
+ } while (is_success && is_dav);
+
+ /* we have reached the end of paths we are allowed to
+ * chdir up to (or couldn't chdir up at all) */
+
+ /* check if we at all have a good path */
+ if (last_good_path == NULL)
+ {
+ if (!is_success)
+ g_vfs_job_failed (G_VFS_JOB (job),
+ G_IO_ERROR,G_IO_ERROR_FAILED,
+ _("HTTP Error: %s"), msg->reason_phrase);
+ else
+ g_vfs_job_failed (G_VFS_JOB (job),
+ G_IO_ERROR,G_IO_ERROR_FAILED,
+ _("Not a WebDAV enabled share"));
+ return;
+ }
+
+ /* Set the working path in mount path */
+ g_free (mount_base->path);
+ mount_base->path = last_good_path;
+
+ /* dup the mountspec, but only copy known fields */
+ mount_spec = g_mount_spec_dup_known (mount_spec);
+ g_mount_spec_set_mount_prefix (mount_spec, mount_base->path);
+
+ g_vfs_backend_set_mount_spec (G_VFS_BACKEND (backend), mount_spec);
+ g_vfs_backend_set_icon_name (G_VFS_BACKEND (backend), "folder-remote");
- data->signal_id = g_signal_connect (session, "authenticate",
- G_CALLBACK (soup_authenticate), data);
+ /* cleanup */
+ g_mount_spec_unref (mount_spec);
+ g_object_unref (msg);
- g_vfs_job_set_backend_data (G_VFS_JOB (job), data, mount_op_data_free);
+ /* switch the signal handler */
+ g_signal_handler_disconnect (session, signal_id);
+ g_signal_connect (session, "authenticate",
+ G_CALLBACK (soup_authenticate_from_data),
+ info);
+ g_vfs_job_succeeded (G_VFS_JOB (job));
g_print ("- mount\n");
- return TRUE;
}
+/* *** query_info () *** */
static void
-query_info_ready (SoupSession *session,
- SoupMessage *msg,
- gpointer user_data)
-{
- GVfsBackendDav *backend;
- GVfsJobQueryInfo *job;
- Multistatus ms;
- xmlNodeIter iter;
- SoupURI *base;
- gboolean res;
- GError *error;
-
- job = G_VFS_JOB_QUERY_INFO (user_data);
- backend = G_VFS_BACKEND_DAV (job->backend);
+do_query_info (GVfsBackend *backend,
+ GVfsJobQueryInfo *job,
+ const char *filename,
+ GFileQueryInfoFlags flags,
+ GFileInfo *info,
+ GFileAttributeMatcher *matcher)
+{
+ SoupMessage *msg;
+ Multistatus ms;
+ xmlNodeIter iter;
+ SoupURI *base;
+ gboolean res;
+ GError *error;
+
base = G_VFS_BACKEND_HTTP (backend)->mount_base;
error = NULL;
+ msg = propfind_request_new (backend, filename, 0, NULL);
+
+ if (msg == NULL)
+ {
+ g_vfs_job_failed (G_VFS_JOB (job),
+ G_IO_ERROR,G_IO_ERROR_FAILED,
+ _("Could not create request"));
+
+ return;
+ }
+
+ message_add_apply_to_redirect_header (msg, flags);
+
+ soup_session_send_message (G_VFS_BACKEND_HTTP (backend)->session, msg);
+
res = multistatus_parse (msg, &ms, &error);
+ g_object_unref (msg);
if (res == FALSE)
{
@@ -1023,93 +1134,55 @@
}
}
+ multistatus_free (&ms);
+
if (res)
- g_vfs_job_succeeded (G_VFS_JOB (job));
+ g_vfs_job_succeeded (G_VFS_JOB (job));
else
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR,G_IO_ERROR_FAILED,
- _("Response invalid"));
+ g_vfs_job_failed (G_VFS_JOB (job),
+ G_IO_ERROR,G_IO_ERROR_FAILED,
+ _("Response invalid"));
- multistatus_free (&ms);
}
-/* *** query_info () *** */
-static gboolean
-try_query_info (GVfsBackend *backend,
- GVfsJobQueryInfo *job,
- const char *filename,
- GFileQueryInfoFlags flags,
- GFileInfo *info,
- GFileAttributeMatcher *attribute_matcher)
-{
- SoupMessage *msg;
- gulong len;
- char *request;
- char *redirect_header;
- len = 0;
- msg = message_new_from_filename (backend, "PROPFIND", filename);
+/* *** enumerate *** */
+static void
+do_enumerate (GVfsBackend *backend,
+ GVfsJobEnumerate *job,
+ const char *filename,
+ GFileAttributeMatcher *matcher,
+ GFileQueryInfoFlags flags)
+{
+ GVfsBackendHttp *backend_http;
+ SoupMessage *msg;
+ Multistatus ms;
+ xmlNodeIter iter;
+ gboolean res;
+ SoupURI *base;
+ GError *error;
+
+ backend_http = G_VFS_BACKEND_HTTP (backend);
+ base = backend_http->mount_base;
+ error = NULL;
- request = create_propfind_request (attribute_matcher, &len);
+ msg = propfind_request_new (backend, filename, 1, NULL);
- if (request == NULL || msg == NULL)
+ if (msg == NULL)
{
g_vfs_job_failed (G_VFS_JOB (job),
G_IO_ERROR,G_IO_ERROR_FAILED,
_("Could not create request"));
-
- if (msg)
- g_object_unref (msg);
-
- g_free (request);
- return TRUE;
+ return;
}
- soup_message_headers_append (msg->request_headers, "Depth", "0");
-
- /* RFC 4437 */
- if (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS)
- redirect_header = "F";
- else
- redirect_header = "T";
-
- soup_message_headers_append (msg->request_headers,
- "Apply-To-Redirect-Ref", redirect_header);
+ message_add_apply_to_redirect_header (msg, flags);
- soup_message_set_request (msg, "application/xml",
- SOUP_MEMORY_TAKE,
- request,
- len);
-
- send_message (backend, msg, query_info_ready, job);
- return TRUE;
-}
-
-
-/* *** enumerate *** */
+ soup_session_send_message (backend_http->session, msg);
-
-static void
-enumerate_ready (SoupSession *session,
- SoupMessage *msg,
- gpointer user_data)
-{
- GVfsBackendDav *backend;
- GVfsJobEnumerate *job;
- Multistatus ms;
- xmlNodeIter iter;
- gboolean res;
- SoupURI *base;
- GError *error;
-
-
- job = G_VFS_JOB_ENUMERATE (user_data);
- backend = G_VFS_BACKEND_DAV (job->backend);
- base = G_VFS_BACKEND_HTTP (backend)->mount_base;
- error = NULL;
-
res = multistatus_parse (msg, &ms, &error);
+ g_object_unref (msg);
if (res == FALSE)
{
@@ -1139,60 +1212,10 @@
g_vfs_job_enumerate_add_info (job, info);
}
- g_vfs_job_succeeded (G_VFS_JOB (job)); /* should that be called earlier? */
- g_vfs_job_enumerate_done (G_VFS_JOB_ENUMERATE (job));
multistatus_free (&ms);
-}
-
-static gboolean
-try_enumerate (GVfsBackend *backend,
- GVfsJobEnumerate *job,
- const char *filename,
- GFileAttributeMatcher *attribute_matcher,
- GFileQueryInfoFlags flags)
-{
- SoupMessage *msg;
- gulong len;
- char *request;
- char *redirect_header;
-
- len = 0;
- msg = message_new_from_filename (backend, "PROPFIND", filename);
-
- request = create_propfind_request (attribute_matcher, &len);
- if (request == NULL || msg == NULL)
- {
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR,G_IO_ERROR_FAILED,
- _("Could not create request"));
-
-
- if (msg)
- g_object_unref (msg);
-
- g_free (request);
- return TRUE;
- }
-
- soup_message_headers_append (msg->request_headers, "Depth", "1");
-
- /* RFC 4437 */
- if (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS)
- redirect_header = "F";
- else
- redirect_header = "T";
-
- soup_message_headers_append (msg->request_headers,
- "Apply-To-Redirect-Ref", redirect_header);
-
- soup_message_set_request (msg, "application/xml",
- SOUP_MEMORY_TAKE,
- request,
- len);
-
- send_message (backend, msg, enumerate_ready, job);
- return TRUE;
+ g_vfs_job_succeeded (G_VFS_JOB (job)); /* should that be called earlier? */
+ g_vfs_job_enumerate_done (G_VFS_JOB_ENUMERATE (job));
}
/* ************************************************************************* */
@@ -1320,7 +1343,7 @@
- uri = g_vfs_backend_uri_for_filename (backend, filename);
+ uri = g_vfs_backend_uri_for_filename (backend, filename, FALSE);
if (etag)
{
@@ -1328,7 +1351,6 @@
msg = soup_message_new_from_uri (SOUP_METHOD_HEAD, uri);
soup_uri_free (uri);
- soup_message_headers_append (msg->request_headers, "User-Agent", "gvfs/" VERSION);
soup_message_headers_append (msg->request_headers, "If-Match", etag);
g_vfs_job_set_backend_data (G_VFS_JOB (job), op_backend, NULL);
@@ -1444,6 +1466,31 @@
return TRUE;
}
+static void
+do_make_directory (GVfsBackend *backend,
+ GVfsJobMakeDirectory *job,
+ const char *filename)
+{
+ SoupMessage *msg;
+ guint status;
+ char *to_free;
+
+ msg = message_new_from_filename_full (backend, "MKCOL", filename, TRUE);
+
+ status = soup_session_send_message (G_VFS_BACKEND_HTTP (backend)->session, msg);
+
+ /* TODO: error reporting sucks */
+ if (! SOUP_STATUS_IS_SUCCESSFUL (status))
+ g_vfs_job_failed (G_VFS_JOB (job),
+ G_IO_ERROR,G_IO_ERROR_FAILED,
+ _("HTTP Error: %s"), msg->reason_phrase);
+ else
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+
+ g_object_unref (msg);
+}
+
+
/* ************************************************************************* */
/* */
@@ -1458,12 +1505,14 @@
backend_class = G_VFS_BACKEND_CLASS (klass);
- backend_class->try_mount = try_mount;
- backend_class->try_query_info = try_query_info;
- backend_class->try_enumerate = try_enumerate;
+ backend_class->try_mount = NULL;
+ backend_class->mount = do_mount;
+ backend_class->try_query_info = NULL;
+ backend_class->query_info = do_query_info;
+ backend_class->enumerate = do_enumerate;
backend_class->try_create = try_create;
backend_class->try_replace = try_replace;
backend_class->try_write = try_write;
backend_class->try_close_write = try_close_write;
-
+ backend_class->make_directory = do_make_directory;
}
Modified: trunk/daemon/gvfsbackendhttp.c
==============================================================================
--- trunk/daemon/gvfsbackendhttp.c (original)
+++ trunk/daemon/gvfsbackendhttp.c Mon Feb 25 14:55:01 2008
@@ -79,8 +79,11 @@
backend->session = soup_session_sync_new ();
}
+
SoupURI *
-g_vfs_backend_uri_for_filename (GVfsBackend *backend, const char *filename)
+g_vfs_backend_uri_for_filename (GVfsBackend *backend,
+ const char *filename,
+ gboolean is_dir)
{
GVfsBackendHttp *op_backend;
SoupURI *uri;
@@ -95,8 +98,15 @@
/* Otherwise, we append filename to mount_base (which is assumed to
* be a directory in this case).
+ *
+ * Add a "/" in cases where it is likely that the url is going
+ * to be a directory to avoid redirections
*/
- path = g_build_path ("/", uri->path, filename, NULL);
+ if (is_dir == FALSE || g_str_has_suffix (filename, "/"))
+ path = g_build_path ("/", uri->path, filename, NULL);
+ else
+ path = g_build_path ("/", uri->path, filename, "/", NULL);
+
g_free (uri->path);
uri->path = g_uri_escape_string (path, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH,
FALSE);
@@ -191,20 +201,32 @@
}
SoupMessage *
-message_new_from_filename (GVfsBackend *backend,
- const char *method,
- const char *filename)
+message_new_from_filename_full (GVfsBackend *backend,
+ const char *method,
+ const char *filename,
+ gboolean is_dir)
{
SoupMessage *msg;
SoupURI *uri;
- uri = g_vfs_backend_uri_for_filename (backend, filename);
+ uri = g_vfs_backend_uri_for_filename (backend, filename, is_dir);
msg = message_new_from_uri (method, uri);
soup_uri_free (uri);
return msg;
}
+
+SoupMessage *
+message_new_from_filename (GVfsBackend *backend,
+ const char *method,
+ const char *filename)
+{
+ return message_new_from_filename_full (backend, method, filename, FALSE);
+}
+
+
+
/* ************************************************************************* */
/* virtual functions overrides */
Modified: trunk/daemon/gvfsbackendhttp.h
==============================================================================
--- trunk/daemon/gvfsbackendhttp.h (original)
+++ trunk/daemon/gvfsbackendhttp.h Mon Feb 25 14:55:01 2008
@@ -53,7 +53,14 @@
};
GType g_vfs_backend_http_get_type (void) G_GNUC_CONST;
-SoupURI * g_vfs_backend_uri_for_filename (GVfsBackend *backend, const char *filename);
+SoupURI * g_vfs_backend_uri_for_filename (GVfsBackend *backend,
+ const char *filename,
+ gboolean is_dir);
+
+SoupMessage * message_new_from_filename_full (GVfsBackend *backend,
+ const char *method,
+ const char *filename,
+ gboolean is_dir);
SoupMessage * message_new_from_filename (GVfsBackend *backend,
const char *method,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]