1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-request-file.c: file: URI request object
5 * Copyright (C) 2009, 2010 Red Hat, Inc.
6 * Copyright (C) 2010 Igalia, S.L.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
28 #define LIBSOUP_USE_UNSTABLE_REQUEST_API
30 #include <glib/gi18n.h>
32 #include "soup-request-file.h"
33 #include "soup-directory-input-stream.h"
34 #include "soup-requester.h"
37 G_DEFINE_TYPE (SoupRequestFile, soup_request_file, SOUP_TYPE_REQUEST)
39 struct _SoupRequestFilePrivate {
47 soup_request_file_init (SoupRequestFile *file)
49 file->priv = G_TYPE_INSTANCE_GET_PRIVATE (file, SOUP_TYPE_REQUEST_FILE, SoupRequestFilePrivate);
51 file->priv->size = -1;
55 soup_request_file_finalize (GObject *object)
57 SoupRequestFile *file = SOUP_REQUEST_FILE (object);
59 if (file->priv->gfile)
60 g_object_unref (file->priv->gfile);
61 g_free (file->priv->mime_type);
63 G_OBJECT_CLASS (soup_request_file_parent_class)->finalize (object);
67 soup_request_file_check_uri (SoupRequest *request,
71 /* "file:/foo" is not valid */
75 /* but it must be "file:///..." or "file://localhost/..." */
76 if (uri->scheme == SOUP_URI_SCHEME_FILE &&
78 g_ascii_strcasecmp (uri->host, "localhost") != 0)
85 soup_request_file_ensure_file (SoupRequestFile *file,
86 GCancellable *cancellable,
91 if (file->priv->gfile)
94 uri = soup_request_get_uri (SOUP_REQUEST (file));
95 if (uri->scheme == SOUP_URI_SCHEME_FILE) {
96 gchar *decoded_uri = soup_uri_decode (uri->path);
99 file->priv->gfile = g_file_new_for_path (decoded_uri);
100 g_free (decoded_uri);
106 g_set_error (error, SOUP_REQUESTER_ERROR, SOUP_REQUESTER_ERROR_UNSUPPORTED_URI_SCHEME,
107 _("Unsupported URI scheme '%s'"), uri->scheme);
111 static GInputStream *
112 soup_request_file_send (SoupRequest *request,
113 GCancellable *cancellable,
116 SoupRequestFile *file = SOUP_REQUEST_FILE (request);
117 GInputStream *stream;
118 GError *my_error = NULL;
120 if (!soup_request_file_ensure_file (file, cancellable, error))
123 stream = G_INPUT_STREAM (g_file_read (file->priv->gfile,
124 cancellable, &my_error));
125 if (stream == NULL) {
126 if (g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY)) {
127 GFileEnumerator *enumerator;
128 g_clear_error (&my_error);
129 enumerator = g_file_enumerate_children (file->priv->gfile,
131 G_FILE_QUERY_INFO_NONE,
135 stream = soup_directory_input_stream_new (enumerator,
136 soup_request_get_uri (request));
137 g_object_unref (enumerator);
138 file->priv->mime_type = g_strdup ("text/html");
141 g_propagate_error (error, my_error);
143 GFileInfo *info = g_file_query_info (file->priv->gfile,
144 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
145 G_FILE_ATTRIBUTE_STANDARD_SIZE,
146 0, cancellable, NULL);
148 const char *content_type;
149 file->priv->size = g_file_info_get_size (info);
150 content_type = g_file_info_get_content_type (info);
153 file->priv->mime_type = g_content_type_get_mime_type (content_type);
154 g_object_unref (info);
162 soup_request_file_send_async_thread (GSimpleAsyncResult *res,
164 GCancellable *cancellable)
166 GInputStream *stream;
167 SoupRequest *request;
168 GError *error = NULL;
170 request = SOUP_REQUEST (object);
172 stream = soup_request_file_send (request, cancellable, &error);
174 if (stream == NULL) {
175 g_simple_async_result_set_from_error (res, error);
176 g_error_free (error);
178 g_simple_async_result_set_op_res_gpointer (res, stream, g_object_unref);
183 soup_request_file_send_async (SoupRequest *request,
184 GCancellable *cancellable,
185 GAsyncReadyCallback callback,
188 GSimpleAsyncResult *res;
190 res = g_simple_async_result_new (G_OBJECT (request), callback, user_data, soup_request_file_send_async);
192 g_simple_async_result_run_in_thread (res, soup_request_file_send_async_thread, G_PRIORITY_DEFAULT, cancellable);
193 g_object_unref (res);
196 static GInputStream *
197 soup_request_file_send_finish (SoupRequest *request,
198 GAsyncResult *result,
201 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
203 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == soup_request_file_send_async);
205 if (g_simple_async_result_propagate_error (simple, error))
208 return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
212 soup_request_file_get_content_length (SoupRequest *request)
214 SoupRequestFile *file = SOUP_REQUEST_FILE (request);
216 return file->priv->size;
220 soup_request_file_get_content_type (SoupRequest *request)
222 SoupRequestFile *file = SOUP_REQUEST_FILE (request);
224 if (!file->priv->mime_type)
225 return "application/octet-stream";
227 return file->priv->mime_type;
230 static const char *file_schemes[] = { "file", NULL };
233 soup_request_file_class_init (SoupRequestFileClass *request_file_class)
235 GObjectClass *object_class = G_OBJECT_CLASS (request_file_class);
236 SoupRequestClass *request_class =
237 SOUP_REQUEST_CLASS (request_file_class);
239 g_type_class_add_private (request_file_class, sizeof (SoupRequestFilePrivate));
241 request_class->schemes = file_schemes;
243 object_class->finalize = soup_request_file_finalize;
245 request_class->check_uri = soup_request_file_check_uri;
246 request_class->send = soup_request_file_send;
247 request_class->send_async = soup_request_file_send_async;
248 request_class->send_finish = soup_request_file_send_finish;
249 request_class->get_content_length = soup_request_file_get_content_length;
250 request_class->get_content_type = soup_request_file_get_content_type;
254 soup_request_file_get_file (SoupRequestFile *file)
256 return g_object_ref (file->priv->gfile);