2010-10-13 Sergio Villar Senin <svillar@igalia.com>
[WebKit-https.git] / WebCore / platform / network / soup / cache / soup-directory-input-stream.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2008 Red Hat, Inc.
4  * Copyright (C) 2010 Igalia, S.L.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include "soup-directory-input-stream.h"
27
28 #include <libsoup/soup.h>
29 #include <stdio.h>
30 #include <string.h>
31
32 #define INIT_STRING "<html><head><title>OMG!</title></head><body><table>"
33 #define EXIT_STRING "</table></html>"
34
35 G_DEFINE_TYPE (WebKitSoupDirectoryInputStream, webkit_soup_directory_input_stream, G_TYPE_INPUT_STREAM)
36
37 static SoupBuffer *
38 webkit_soup_directory_input_stream_parse_info (WebKitSoupDirectoryInputStream * stream,
39                                                GFileInfo * info)
40 {
41         SoupBuffer *buffer;
42         GString *string;
43         const char *s;
44         char *escaped, *path, *xml_string;
45
46         if (!g_file_info_get_name (info))
47                 return NULL;
48
49         s = g_file_info_get_display_name (info);
50         if (!s) {
51                 s = g_file_info_get_name (info);
52                 /* FIXME: convert somehow? */
53                 if (!g_utf8_validate (s, -1, NULL))
54                         return NULL;
55         }
56         string = g_string_new ("<tr>");
57
58         xml_string = g_markup_escape_text (s, -1);
59         escaped = g_uri_escape_string (g_file_info_get_name (info), NULL, FALSE);
60         path = g_strconcat (stream->uri, "/", escaped, NULL);
61         g_free (escaped);
62         g_string_append_printf (string, "<td><a href=\"%s\">%s</a></td>", path, xml_string);
63         g_free (path);
64         g_free (xml_string);
65         g_string_append (string, "</tr>");
66
67         buffer = soup_buffer_new (SOUP_MEMORY_TAKE, string->str, string->len);
68         g_string_free (string, FALSE);
69
70         return buffer;
71 }
72
73 static SoupBuffer *
74 webkit_soup_directory_input_stream_read_next_file (WebKitSoupDirectoryInputStream  *stream,
75                                                    GCancellable              *cancellable,
76                                                    GError                   **error)
77 {
78         GFileInfo *info;
79         SoupBuffer *buffer;
80         GError *err = NULL;
81
82         do {
83                 info = g_file_enumerator_next_file (stream->enumerator, cancellable, &err);
84                 if (info == NULL) {
85                         if (err) {
86                                 g_propagate_error (error, err);
87                                 return NULL;
88                         } else if (!stream->done) {
89                                 stream->done = TRUE;
90                                 return soup_buffer_new (SOUP_MEMORY_STATIC,
91                                                         EXIT_STRING,
92                                                         sizeof (EXIT_STRING));
93                         } else {
94                                 return NULL;
95                         }
96                 }
97
98                 buffer = webkit_soup_directory_input_stream_parse_info (stream, info);
99         } while (buffer == NULL);
100
101         return buffer;
102 }
103
104 static gssize
105 webkit_soup_directory_input_stream_read (GInputStream  *input,
106                                          void          *buffer,
107                                          gsize count,
108                                          GCancellable  *cancellable,
109                                          GError       **error)
110 {
111         WebKitSoupDirectoryInputStream *stream = WEBKIT_SOUP_DIRECTORY_INPUT_STREAM (input);
112         gssize total, size;
113
114         for (total = 0; total < count; total += size) {
115                 if (stream->buffer == NULL) {
116                         stream->buffer = webkit_soup_directory_input_stream_read_next_file (stream, cancellable, error);
117                         if (stream->buffer == NULL) {
118                                 /* FIXME: Is this correct or should we forward the error? */
119                                 if (total)
120                                         g_clear_error (error);
121                                 return total;
122                         }
123                 }
124
125                 size = MIN (stream->buffer->length, count - total);
126                 memcpy ((char *)buffer + total, stream->buffer->data, size);
127                 if (size == stream->buffer->length) {
128                         soup_buffer_free (stream->buffer);
129                         stream->buffer = NULL;
130                 } else {
131                         SoupBuffer *sub = soup_buffer_new_subbuffer (stream->buffer,
132                                                                      size,
133                                                                      stream->buffer->length - size);
134                         soup_buffer_free (stream->buffer);
135                         stream->buffer = sub;
136                 }
137         }
138
139         return total;
140 }
141
142 static gboolean
143 webkit_soup_directory_input_stream_close (GInputStream  *input,
144                                           GCancellable  *cancellable,
145                                           GError       **error)
146 {
147         WebKitSoupDirectoryInputStream *stream = WEBKIT_SOUP_DIRECTORY_INPUT_STREAM (input);
148         gboolean result;
149
150         if (stream->buffer) {
151                 soup_buffer_free (stream->buffer);
152                 stream->buffer = NULL;
153         }
154
155         result = g_file_enumerator_close (stream->enumerator,
156                                           cancellable,
157                                           error);
158         g_object_unref (stream->enumerator);
159         stream->enumerator = NULL;
160
161         g_free (stream->uri);
162         stream->uri = NULL;
163
164         return result;
165 }
166
167 static void
168 webkit_soup_directory_input_stream_class_init (WebKitSoupDirectoryInputStreamClass *stream_class)
169 {
170         GInputStreamClass *inputstream_class = G_INPUT_STREAM_CLASS (stream_class);
171
172         inputstream_class->read_fn = webkit_soup_directory_input_stream_read;
173         inputstream_class->close_fn = webkit_soup_directory_input_stream_close;
174 }
175
176 static void
177 webkit_soup_directory_input_stream_init (WebKitSoupDirectoryInputStream *stream)
178 {
179         stream->buffer = soup_buffer_new (SOUP_MEMORY_STATIC,
180                                           INIT_STRING,
181                                           sizeof (INIT_STRING));
182 }
183
184 GInputStream *
185 webkit_soup_directory_input_stream_new (GFileEnumerator *enumerator,
186                                         SoupURI         *uri)
187 {
188         GInputStream *stream;
189
190         g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL);
191         g_return_val_if_fail (uri != NULL, NULL);
192
193         stream = g_object_new (WEBKIT_TYPE_SOUP_DIRECTORY_INPUT_STREAM, NULL);
194
195         WEBKIT_SOUP_DIRECTORY_INPUT_STREAM (stream)->enumerator = g_object_ref (enumerator);
196         WEBKIT_SOUP_DIRECTORY_INPUT_STREAM (stream)->uri = soup_uri_to_string (uri, FALSE);
197
198         return stream;
199 }
200