diff options
Diffstat (limited to 'daemon/gvfsbackendhttp.c')
-rw-r--r-- | daemon/gvfsbackendhttp.c | 675 |
1 files changed, 0 insertions, 675 deletions
diff --git a/daemon/gvfsbackendhttp.c b/daemon/gvfsbackendhttp.c deleted file mode 100644 index 04501e99..00000000 --- a/daemon/gvfsbackendhttp.c +++ /dev/null @@ -1,675 +0,0 @@ -/* GIO - GLib Input, Output and Streaming Library - * - * Copyright (C) 2008 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., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - * - * Author: Christian Kellner <gicmo@gnome.org> - */ - -#include <config.h> - -#include <sys/types.h> -#include <sys/stat.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> - -#include <glib/gstdio.h> -#include <glib/gi18n.h> -#include <gio/gio.h> - -#include <libsoup/soup.h> -#include "gvfsbackendhttp.h" -#include "gvfsjobopenforread.h" -#include "gvfsjobread.h" -#include "gvfsjobseekread.h" -#include "gvfsjobopenforwrite.h" -#include "gvfsjobwrite.h" -#include "gvfsjobseekwrite.h" -#include "gvfsjobsetdisplayname.h" -#include "gvfsjobqueryinfo.h" -#include "gvfsjobqueryfsinfo.h" -#include "gvfsjobqueryattributes.h" -#include "gvfsjobenumerate.h" -#include "gvfsdaemonprotocol.h" - -#include "soup-input-stream.h" - - -G_DEFINE_TYPE (GVfsBackendHttp, g_vfs_backend_http, G_VFS_TYPE_BACKEND) - -static void -g_vfs_backend_http_finalize (GObject *object) -{ - GVfsBackendHttp *backend; - - backend = G_VFS_BACKEND_HTTP (object); - - if (backend->mount_base) - soup_uri_free (backend->mount_base); - - soup_session_abort (backend->session); - g_object_unref (backend->session); - - soup_session_abort (backend->session_async); - g_object_unref (backend->session_async); - - - if (G_OBJECT_CLASS (g_vfs_backend_http_parent_class)->finalize) - (*G_OBJECT_CLASS (g_vfs_backend_http_parent_class)->finalize) (object); -} - -#define DEBUG_MAX_BODY_SIZE (100 * 1024 * 1024) - -static void -g_vfs_backend_http_init (GVfsBackendHttp *backend) -{ - const char *debug; - - g_vfs_backend_set_user_visible (G_VFS_BACKEND (backend), FALSE); - - backend->session = soup_session_sync_new_with_options ("user-agent", - "gvfs/" VERSION, - NULL); - - backend->session_async = soup_session_async_new_with_options ("user-agent", - "gvfs/" VERSION, - NULL); - - /* Logging */ - debug = g_getenv ("GVFS_HTTP_DEBUG"); - if (debug) - { - SoupLogger *logger; - SoupLoggerLogLevel level; - - if (g_ascii_strcasecmp (debug, "all") || - g_ascii_strcasecmp (debug, "body")) - level = SOUP_LOGGER_LOG_BODY; - else if (g_ascii_strcasecmp (debug, "header")) - level = SOUP_LOGGER_LOG_HEADERS; - else - level = SOUP_LOGGER_LOG_MINIMAL; - - logger = soup_logger_new (level, DEBUG_MAX_BODY_SIZE); - soup_logger_attach (logger, backend->session); - soup_logger_attach (logger, backend->session_async); - g_object_unref (logger); - } - -} - -/* ************************************************************************* */ -/* public utility functions */ - -SoupURI * -http_backend_uri_for_filename (GVfsBackend *backend, - const char *filename, - gboolean is_dir) -{ - GVfsBackendHttp *op_backend; - SoupURI *uri; - char *path; - - op_backend = G_VFS_BACKEND_HTTP (backend); - uri = soup_uri_copy (op_backend->mount_base); - - /* "/" means "whatever mount_base is" */ - if (!strcmp (filename, "/")) - return uri; - - /* 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 - */ - 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); - g_free (path); - - return uri; -} - -char * -http_uri_get_basename (const char *uri_str) -{ - const char *parent; - const char *path; - char *to_free; - char *basename; - size_t len; - - if (uri_str == NULL || *uri_str == '\0') - return NULL; - - path = uri_str; - - /* remove any leading slashes */ - while (*path == '/' || *path == ' ') - path++; - - len = strlen (path); - - if (len == 0) - return g_strdup ("/"); - - /* remove any trailing slashes */ - while (path[len - 1] == '/' || path[len - 1] == ' ') - len--; - - parent = g_strrstr_len (path, len, "/"); - - if (parent) - { - parent++; /* skip the found / char */ - to_free = g_strndup (parent, (len - (parent - path))); - } - else - to_free = g_strndup (path, len); - - basename = soup_uri_decode (to_free); - g_free (to_free); - - return basename; -} - -guint -http_error_code_from_status (guint status) -{ - switch (status) { - - case SOUP_STATUS_CANT_RESOLVE: - case SOUP_STATUS_CANT_RESOLVE_PROXY: - return G_IO_ERROR_HOST_NOT_FOUND; - - case SOUP_STATUS_CANCELLED: - return G_IO_ERROR_CANCELLED; - - case SOUP_STATUS_UNAUTHORIZED: - case SOUP_STATUS_PAYMENT_REQUIRED: - case SOUP_STATUS_FORBIDDEN: - return G_IO_ERROR_PERMISSION_DENIED; - - case SOUP_STATUS_NOT_FOUND: - case SOUP_STATUS_GONE: - return G_IO_ERROR_NOT_FOUND; - - case SOUP_STATUS_GATEWAY_TIMEOUT: - return G_IO_ERROR_TIMED_OUT; - } - - return G_IO_ERROR_FAILED; -} - - -static void -g_vfs_job_failed_from_http_status (GVfsJob *job, guint status_code, const char *message) -{ - switch (status_code) { - - case SOUP_STATUS_NOT_FOUND: - g_vfs_job_failed_literal (job, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - message); - break; - - case SOUP_STATUS_UNAUTHORIZED: - case SOUP_STATUS_PAYMENT_REQUIRED: - case SOUP_STATUS_FORBIDDEN: - g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, - _("HTTP Client Error: %s"), message); - break; - default: - g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_FAILED, - _("HTTP Error: %s"), message); - } -} - -guint -http_backend_send_message (GVfsBackend *backend, - SoupMessage *msg) -{ - GVfsBackendHttp *op_backend = G_VFS_BACKEND_HTTP (backend); - - return soup_session_send_message (op_backend->session, msg); -} - -void -http_backend_queue_message (GVfsBackend *backend, - SoupMessage *msg, - SoupSessionCallback callback, - gpointer user_data) -{ - GVfsBackendHttp *op_backend = G_VFS_BACKEND_HTTP (backend); - - soup_session_queue_message (op_backend->session_async, msg, - callback, user_data); -} -/* ************************************************************************* */ -/* virtual functions overrides */ - -static gboolean -try_mount (GVfsBackend *backend, - GVfsJobMount *job, - GMountSpec *mount_spec, - GMountSource *mount_source, - gboolean is_automount) -{ - GVfsBackendHttp *op_backend; - const char *uri_str; - char *path; - SoupURI *uri; - GMountSpec *real_mount_spec; - - op_backend = G_VFS_BACKEND_HTTP (backend); - - uri = NULL; - uri_str = g_mount_spec_get (mount_spec, "uri"); - - if (uri_str) - uri = soup_uri_new (uri_str); - - g_print ("+ try_mount: %s\n", uri_str ? uri_str : "(null)"); - - if (uri == NULL) - { - g_vfs_job_failed (G_VFS_JOB (job), - G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Invalid mount spec")); - return TRUE; - } - - real_mount_spec = g_mount_spec_new ("http"); - g_mount_spec_set (real_mount_spec, "uri", uri_str); - - if (uri->path != NULL) - { - path = g_uri_unescape_string (uri->path, "/"); - g_free (real_mount_spec->mount_prefix); - real_mount_spec->mount_prefix = g_mount_spec_canonicalize_path (path); - g_free (path); - } - - g_vfs_backend_set_mount_spec (backend, real_mount_spec); - - op_backend->mount_base = uri; - - g_vfs_job_succeeded (G_VFS_JOB (job)); - return TRUE; -} - -/* *** open_read () *** */ -static void -open_for_read_ready (GObject *source_object, - GAsyncResult *result, - gpointer user_data) -{ - GInputStream *stream; - GVfsJob *job; - gboolean res; - gboolean can_seek; - GError *error; - - stream = G_INPUT_STREAM (source_object); - error = NULL; - job = G_VFS_JOB (user_data); - - res = soup_input_stream_send_finish (stream, - result, - &error); - if (res == FALSE) - { - g_vfs_job_failed_literal (G_VFS_JOB (job), - error->domain, - error->code, - error->message); - - g_error_free (error); - return; - } - - 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); - g_vfs_job_open_for_read_set_handle (G_VFS_JOB_OPEN_FOR_READ (job), stream); - g_vfs_job_succeeded (job); -} - -static gboolean -try_open_for_read (GVfsBackend *backend, - GVfsJobOpenForRead *job, - const char *filename) -{ - GVfsBackendHttp *op_backend; - GInputStream *stream; - SoupMessage *msg; - SoupURI *uri; - - op_backend = G_VFS_BACKEND_HTTP (backend); - uri = http_backend_uri_for_filename (backend, filename, FALSE); - msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri); - soup_uri_free (uri); - - stream = soup_input_stream_new (op_backend->session_async, msg); - g_object_unref (msg); - - soup_input_stream_send_async (stream, - G_PRIORITY_DEFAULT, - G_VFS_JOB (job)->cancellable, - open_for_read_ready, - job); - return TRUE; -} - -/* *** read () *** */ -static void -read_ready (GObject *source_object, - GAsyncResult *result, - gpointer user_data) -{ - GInputStream *stream; - GVfsJob *job; - GError *error; - gssize nread; - - stream = G_INPUT_STREAM (source_object); - error = NULL; - job = G_VFS_JOB (user_data); - - nread = g_input_stream_read_finish (stream, result, &error); - - if (nread < 0) - { - g_vfs_job_failed_literal (G_VFS_JOB (job), - error->domain, - error->code, - error->message); - - g_error_free (error); - return; - } - - g_vfs_job_read_set_size (G_VFS_JOB_READ (job), nread); - g_vfs_job_succeeded (job); - -} - -static gboolean -try_read (GVfsBackend *backend, - GVfsJobRead *job, - GVfsBackendHandle handle, - char *buffer, - gsize bytes_requested) -{ - GInputStream *stream; - - stream = G_INPUT_STREAM (handle); - - g_input_stream_read_async (stream, - buffer, - bytes_requested, - G_PRIORITY_DEFAULT, - G_VFS_JOB (job)->cancellable, - read_ready, - job); - return TRUE; -} - -static gboolean -try_seek_on_read (GVfsBackend *backend, - GVfsJobSeekRead *job, - GVfsBackendHandle handle, - goffset offset, - GSeekType type) -{ - GInputStream *stream; - GError *error = NULL; - - stream = G_INPUT_STREAM (handle); - - if (!g_seekable_seek (G_SEEKABLE (stream), offset, type, - G_VFS_JOB (job)->cancellable, &error)) - { - g_vfs_job_failed_literal (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, - GAsyncResult *result, - gpointer user_data) -{ - GInputStream *stream; - GVfsJob *job; - GError *error; - gboolean res; - - job = G_VFS_JOB (user_data); - stream = G_INPUT_STREAM (source_object); - res = g_input_stream_close_finish (stream, - result, - &error); - if (res == FALSE) - { - g_vfs_job_failed_literal (G_VFS_JOB (job), - error->domain, - error->code, - error->message); - - g_error_free (error); - } - else - g_vfs_job_succeeded (job); - - g_object_unref (stream); -} - -static gboolean -try_close_read (GVfsBackend *backend, - GVfsJobCloseRead *job, - GVfsBackendHandle handle) -{ - GInputStream *stream; - - stream = G_INPUT_STREAM (handle); - - g_input_stream_close_async (stream, - G_PRIORITY_DEFAULT, - G_VFS_JOB (job)->cancellable, - close_read_ready, - job); - return TRUE; -} - - -/* *** query_info () *** */ - -static void -query_info_ready (SoupSession *session, - SoupMessage *msg, - gpointer user_data) -{ - GFileAttributeMatcher *matcher; - GVfsJobQueryInfo *job; - const SoupURI *uri; - const char *text; - GFileInfo *info; - char *basename; - - job = G_VFS_JOB_QUERY_INFO (user_data); - info = job->file_info; - matcher = job->attribute_matcher; - - 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); - return; - } - - uri = soup_message_get_uri (msg); - basename = http_uri_get_basename (uri->path); - - g_print ("basename:%s\n", basename); - - /* read http/1.1 rfc, until then we copy the local files - * behaviour */ - if (basename != NULL && - g_file_attribute_matcher_matches (matcher, - G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME)) - { - char *display_name = g_filename_display_name (basename); - - if (strstr (display_name, "\357\277\275") != NULL) - { - char *p = display_name; - display_name = g_strconcat (display_name, _(" (invalid encoding)"), NULL); - g_free (p); - } - - g_file_info_set_display_name (info, display_name); - g_free (display_name); - } - - if (basename != NULL && - g_file_attribute_matcher_matches (matcher, - G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME)) - { - char *edit_name = g_filename_display_name (basename); - g_file_info_set_edit_name (info, edit_name); - g_free (edit_name); - } - - g_free (basename); - - - text = soup_message_headers_get (msg->response_headers, - "Content-Length"); - if (text) - { - guint64 size = g_ascii_strtoull (text, NULL, 10); - g_file_info_set_size (info, size); - } - - - text = soup_message_headers_get (msg->response_headers, - "Content-Type"); - if (text) - { - char *p = strchr (text, ';'); - - if (p != NULL) - { - char *tmp = g_strndup (text, p - text); - g_file_info_set_content_type (info, tmp); - g_free (tmp); - } - else - g_file_info_set_content_type (info, text); - } - - - text = soup_message_headers_get (msg->response_headers, - "Last-Modified"); - if (text) - { - SoupDate *sd; - GTimeVal tv; - - sd = soup_date_new_from_string(text); - if (sd) - { - soup_date_to_timeval (sd, &tv); - g_file_info_set_modification_time (info, &tv); - soup_date_free (sd); - } - } - - - text = soup_message_headers_get (msg->response_headers, - "ETag"); - if (text) - { - g_file_info_set_attribute_string (info, - G_FILE_ATTRIBUTE_ETAG_VALUE, - text); - } - - - g_vfs_job_succeeded (G_VFS_JOB (job)); -} - - -static gboolean -try_query_info (GVfsBackend *backend, - GVfsJobQueryInfo *job, - const char *filename, - GFileQueryInfoFlags flags, - GFileInfo *info, - GFileAttributeMatcher *attribute_matcher) -{ - SoupMessage *msg; - SoupURI *uri; - - uri = http_backend_uri_for_filename (backend, filename, FALSE); - msg = soup_message_new_from_uri (SOUP_METHOD_HEAD, uri); - soup_uri_free (uri); - - http_backend_queue_message (backend, msg, query_info_ready, job); - - return TRUE; -} - - -static void -g_vfs_backend_http_class_init (GVfsBackendHttpClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GVfsBackendClass *backend_class; - - gobject_class->finalize = g_vfs_backend_http_finalize; - - backend_class = G_VFS_BACKEND_CLASS (klass); - - 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; - -} |