summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2018-02-13 09:13:40 +0200
committerSergey Poznyakoff <gray@gnu.org>2018-02-13 09:19:08 +0200
commit89aa3e4621f3ab255a59091d3a4d6686fd89516a (patch)
tree85b98688aaddb1e4420172cf977e5282bb97c41b
parent2fa19a04b42557ffc78e47a7d53f2911553c8124 (diff)
downloadfileserv-89aa3e4621f3ab255a59091d3a4d6686fd89516a.tar.gz
fileserv-89aa3e4621f3ab255a59091d3a4d6686fd89516a.tar.bz2
Initial support for auto-generated directory indexes
* src/Makefile.am: Add new sources. Build defidx.h * src/defidx.html: New file. * src/dirconfig.c (dirconfig_free): Handle NULL argument. * src/fileserv.c (index_css, tmpdir): New globals. (get_file_name): Rewrite. (fileserv_handler): Rewrite. * src/fileserv.h (index_css, tmpdir): New externs. * src/ftoc.sed: New file. * src/idx.c: New file. * src/wordsplit.c (expvar): Gracefully handle NULL values in ENV_KV environment. * src/wordsplit.h: Fix typo in a comment.
-rw-r--r--src/.gitignore1
-rw-r--r--src/Makefile.am7
-rw-r--r--src/defidx.html71
-rw-r--r--src/dirconfig.c14
-rw-r--r--src/fileserv.c192
-rw-r--r--src/fileserv.h2
-rw-r--r--src/ftoc.sed23
-rw-r--r--src/idx.c610
-rw-r--r--src/wordsplit.c11
-rw-r--r--src/wordsplit.h4
10 files changed, 870 insertions, 65 deletions
diff --git a/src/.gitignore b/src/.gitignore
index 31a0273..633d03f 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1 +1,2 @@
1fileserv 1fileserv
2defidx.h
diff --git a/src/Makefile.am b/src/Makefile.am
index b9dcfe8..c2fabca 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,9 +1,14 @@
1bin_PROGRAMS=fileserv 1bin_PROGRAMS=fileserv
2fileserv_SOURCES=fileserv.c runas.c fileserv.h logger.c pidfile.c\ 2fileserv_SOURCES=fileserv.c runas.c fileserv.h logger.c pidfile.c\
3 wordsplit.c wordsplit.h catfile.c dirconfig.c 3 wordsplit.c wordsplit.h catfile.c dirconfig.c idx.c defidx.h
4BUILT_SOURCES=defidx.h
4if FSRV_WRAP 5if FSRV_WRAP
5 fileserv_SOURCES += wrapacl.c 6 fileserv_SOURCES += wrapacl.c
6endif 7endif
7dist_man_MANS=fileserv.8 8dist_man_MANS=fileserv.8
8LDADD = ../mimetypes/libmimetypes.a 9LDADD = ../mimetypes/libmimetypes.a
9AM_CPPFLAGS = -I $(top_srcdir)/mimetypes 10AM_CPPFLAGS = -I $(top_srcdir)/mimetypes
11EXTRA_DIST=ftoc.sed defidx.html
12.html.h:
13 $(AM_V_GEN)sed -f $(srcdir)/ftoc.sed $< > $@
14
diff --git a/src/defidx.html b/src/defidx.html
new file mode 100644
index 0000000..83935bd
--- /dev/null
+++ b/src/defidx.html
@@ -0,0 +1,71 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
2<html>
3 <head>
4 <title>Index of {% $URI %}</title>
5 {% if $INDEXCSS %}
6 <link rel="stylesheet" href="{% $INDEXCSS %}" type="text/css">
7 {% endif %}
8 </head>
9 <body>
10 <h1 id="indextitle">Index of {% $URI %}</h1>
11 <table id="indexlist">
12 <tr class="indexhead">
13 <th class="indexcolicon">
14 {% if $(icon blank) %}
15 <img src="{% $(icon blank) %}" alt="[ICO]">
16 {% else %}
17 [ICO]
18 {% endif %}
19 </th>
20 <th class="indexcolname">
21 <a href="?C=N;O=D">Name</a>
22 </th>
23 <th class="indexcollastmod">
24 <a href="?C=M;O=A">Last modified</a>
25 </th>
26 <th class="indexcolsize">
27 <a href="?C=S;O=A">Size</a>
28 </th>
29 <th class="indexcoldesc">
30 <a href="?C=D;O=A">Description</a>
31 </th>
32 </tr>
33 <tr class="indexbreakrow">
34 <th colspan="5"><hr></th>
35 </tr>
36 <tr class="even">
37 <td class="indexcolicon">
38 {% if $(icon back) %}
39 <img src="{% $(icon 'back') %}" alt="[PARENTDIR]">
40 {% else %}
41 [PARENTDIR]
42 {% endif %}
43 </td>
44 <td class="indexcolname">
45 <a href="/">Parent Directory</a>
46 </td>
47 <td class="indexcollastmod">&nbsp;</td>
48 <td class="indexcolsize"> - </td>
49 <td>&nbsp;</td>
50 </tr>
51 {% loop %}
52 <tr class="{% $ROWCLASS %}">
53 <td class="indexcolicon">
54 {% if $(icon $FILETYPE) %}
55 <img src="{% $(icon $FILETYPE) %}" alt="[{% $(alt $FILETYPE) %}]">
56 {% else %}
57 [{% $(alt $FILETYPE) %}]
58 {% endif %}
59 </td>
60 <td class="indexcolname">
61 <a href="{% $FILENAME %}">{% $FILENAME %}</a>
62 </td>
63 <td class="indexcollastmod">{% $FILETIME %}</td>
64 <td class="indexcolsize">{% $FILESIZE %}</td>
65 <td>&nbsp;</td>
66 </tr>
67 {% endloop %}
68 <tr class="indexbreakrow"><th colspan="5"><hr></th></tr>
69 </table>
70</body>
71</html>
diff --git a/src/dirconfig.c b/src/dirconfig.c
index a761401..f5d1146 100644
--- a/src/dirconfig.c
+++ b/src/dirconfig.c
@@ -219,13 +219,15 @@ dirconfig_init(void)
219void 219void
220dirconfig_free(DIRCONFIG *conf) 220dirconfig_free(DIRCONFIG *conf)
221{ 221{
222 if (conf->index_files) { 222 if (conf) {
223 size_t i; 223 if (conf->index_files) {
224 for (i = 0; conf->index_files[i]; i++) 224 size_t i;
225 free(conf->index_files[i]); 225 for (i = 0; conf->index_files[i]; i++)
226 free(conf->index_files); 226 free(conf->index_files[i]);
227 free(conf->index_files);
228 }
229 free(conf);
227 } 230 }
228 free(conf);
229} 231}
230 232
231 233
diff --git a/src/fileserv.c b/src/fileserv.c
index dc218de..f25b6ad 100644
--- a/src/fileserv.c
+++ b/src/fileserv.c
@@ -42,6 +42,8 @@ char *progname;
42int verbose; /* reserved for future use */ 42int verbose; /* reserved for future use */
43char *address = "0.0.0.0"; 43char *address = "0.0.0.0";
44char *forwarded_header = "X-Forwarded-For"; 44char *forwarded_header = "X-Forwarded-For";
45char *index_css;
46char *tmpdir;
45 47
46#ifndef DEFAULT_SERVICE 48#ifndef DEFAULT_SERVICE
47# define DEFAULT_SERVICE "8080" 49# define DEFAULT_SERVICE "8080"
@@ -320,56 +322,111 @@ errno_to_http_code(int ec)
320 return ec == ENOENT ? MHD_HTTP_NOT_FOUND : MHD_HTTP_FORBIDDEN; 322 return ec == ENOENT ? MHD_HTTP_NOT_FOUND : MHD_HTTP_FORBIDDEN;
321} 323}
322 324
325typedef struct file_resp {
326 int fd;
327 char *file_name;
328 DIRCONFIG *conf;
329 struct stat st;
330 char *location;
331} FILE_RESP;
332
333static void
334file_resp_init(FILE_RESP *resp)
335{
336 memset(resp, 0, sizeof(*resp));
337 resp->fd = -1;
338}
339
340static void
341file_resp_free(FILE_RESP *resp)
342{
343 if (resp->fd >= 0)
344 close(resp->fd);
345 free(resp->file_name);
346 dirconfig_free(resp->conf);
347 free(resp->location);
348}
349
323int 350int
324get_file_name(char const *host, char const *url, char **fname, struct stat *stp) 351get_file_name(char const *host, char const *url, FILE_RESP *resp)
325{ 352{
326 struct urimap const *map; 353 struct urimap const *map;
327 char *file_name;
328 char *cf; 354 char *cf;
329 struct stat st; 355
330 DIRCONFIG *conf; 356 file_resp_init(resp);
331 357
332 map = urimap_find(host, url); 358 map = urimap_find(host, url);
333 if (!map) 359 if (!map)
334 return MHD_HTTP_NOT_FOUND; 360 return MHD_HTTP_NOT_FOUND;
335 file_name = catfile_n(map->dir, map->dir_len, url + map->uri_len); 361 resp->file_name = catfile_n(map->dir, map->dir_len, url + map->uri_len);
336 if (lstat(file_name, &st)) 362 if (lstat(resp->file_name, &resp->st))
337 return errno_to_http_code(errno); 363 return errno_to_http_code(errno);
364
365 resp->conf = dirconfig(resp->file_name, map->dir_len);
338 366
339 conf = dirconfig(file_name, map->dir_len); 367 if (S_ISDIR(resp->st.st_mode)) {
368 int res;
369
370 if (url[strlen(url) - 1] != '/') {
371 resp->location = catfile(url, "");
372 return MHD_HTTP_MOVED_PERMANENTLY;
373 }
340 374
341 if (S_ISDIR(st.st_mode)) { 375 res = find_index_file(resp->file_name, resp->conf, &cf,
342 int res = find_index_file(file_name, conf, &cf, &st); 376 &resp->st);
343 if (res == MHD_HTTP_OK) { 377 if (res == MHD_HTTP_OK) {
344 free(file_name); 378 free(resp->file_name);
345 file_name = cf; 379 resp->file_name = cf;
346 } else if (conf->listing) { 380 } else if (resp->conf->listing) {
347 //FIXME 381 //FIXME
348 return MHD_HTTP_FORBIDDEN; 382 char *template = catfile(tmpdir, "idxXXXXXX");
349 } else 383 int fd = mkstemp(template);
384 if (fd == -1) {
385 error("can't create temporary file name: %s",
386 strerror(errno));
387 /*FIXME: leak */
388