xref: /minix3/libexec/httpd/dir-index-bozo.c (revision 340f5e56603e4275faeb89a9aacace41ba22d661)
1*340f5e56SDavid van Moolenbroek /*	$NetBSD: dir-index-bozo.c,v 1.21 2015/08/27 17:12:18 mrg Exp $	*/
2*340f5e56SDavid van Moolenbroek 
3*340f5e56SDavid van Moolenbroek /*	$eterna: dir-index-bozo.c,v 1.20 2011/11/18 09:21:15 mrg Exp $	*/
4*340f5e56SDavid van Moolenbroek 
5*340f5e56SDavid van Moolenbroek /*
6*340f5e56SDavid van Moolenbroek  * Copyright (c) 1997-2014 Matthew R. Green
7*340f5e56SDavid van Moolenbroek  * All rights reserved.
8*340f5e56SDavid van Moolenbroek  *
9*340f5e56SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
10*340f5e56SDavid van Moolenbroek  * modification, are permitted provided that the following conditions
11*340f5e56SDavid van Moolenbroek  * are met:
12*340f5e56SDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
13*340f5e56SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
14*340f5e56SDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
15*340f5e56SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer and
16*340f5e56SDavid van Moolenbroek  *    dedication in the documentation and/or other materials provided
17*340f5e56SDavid van Moolenbroek  *    with the distribution.
18*340f5e56SDavid van Moolenbroek  *
19*340f5e56SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20*340f5e56SDavid van Moolenbroek  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21*340f5e56SDavid van Moolenbroek  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22*340f5e56SDavid van Moolenbroek  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23*340f5e56SDavid van Moolenbroek  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24*340f5e56SDavid van Moolenbroek  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25*340f5e56SDavid van Moolenbroek  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26*340f5e56SDavid van Moolenbroek  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27*340f5e56SDavid van Moolenbroek  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*340f5e56SDavid van Moolenbroek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*340f5e56SDavid van Moolenbroek  * SUCH DAMAGE.
30*340f5e56SDavid van Moolenbroek  *
31*340f5e56SDavid van Moolenbroek  */
32*340f5e56SDavid van Moolenbroek 
33*340f5e56SDavid van Moolenbroek /* this code implements directory index generation for bozohttpd */
34*340f5e56SDavid van Moolenbroek 
35*340f5e56SDavid van Moolenbroek #ifndef NO_DIRINDEX_SUPPORT
36*340f5e56SDavid van Moolenbroek 
37*340f5e56SDavid van Moolenbroek #include <sys/param.h>
38*340f5e56SDavid van Moolenbroek 
39*340f5e56SDavid van Moolenbroek #include <dirent.h>
40*340f5e56SDavid van Moolenbroek #include <errno.h>
41*340f5e56SDavid van Moolenbroek #include <string.h>
42*340f5e56SDavid van Moolenbroek #include <stdlib.h>
43*340f5e56SDavid van Moolenbroek #include <time.h>
44*340f5e56SDavid van Moolenbroek #include <assert.h>
45*340f5e56SDavid van Moolenbroek 
46*340f5e56SDavid van Moolenbroek #include "bozohttpd.h"
47*340f5e56SDavid van Moolenbroek 
48*340f5e56SDavid van Moolenbroek static void
directory_hr(bozohttpd_t * httpd)49*340f5e56SDavid van Moolenbroek directory_hr(bozohttpd_t *httpd)
50*340f5e56SDavid van Moolenbroek {
51*340f5e56SDavid van Moolenbroek 
52*340f5e56SDavid van Moolenbroek 	bozo_printf(httpd,
53*340f5e56SDavid van Moolenbroek 		"<hr noshade align=\"left\" width=\"80%%\">\r\n\r\n");
54*340f5e56SDavid van Moolenbroek }
55*340f5e56SDavid van Moolenbroek 
56*340f5e56SDavid van Moolenbroek /*
57*340f5e56SDavid van Moolenbroek  * output a directory index.  return 1 if it actually did something..
58*340f5e56SDavid van Moolenbroek  */
59*340f5e56SDavid van Moolenbroek int
bozo_dir_index(bozo_httpreq_t * request,const char * dirpath,int isindex)60*340f5e56SDavid van Moolenbroek bozo_dir_index(bozo_httpreq_t *request, const char *dirpath, int isindex)
61*340f5e56SDavid van Moolenbroek {
62*340f5e56SDavid van Moolenbroek 	bozohttpd_t *httpd = request->hr_httpd;
63*340f5e56SDavid van Moolenbroek 	struct stat sb;
64*340f5e56SDavid van Moolenbroek 	struct dirent **de, **deo;
65*340f5e56SDavid van Moolenbroek 	struct tm *tm;
66*340f5e56SDavid van Moolenbroek 	DIR *dp;
67*340f5e56SDavid van Moolenbroek 	char buf[MAXPATHLEN];
68*340f5e56SDavid van Moolenbroek 	char spacebuf[48];
69*340f5e56SDavid van Moolenbroek 	char *file = NULL;
70*340f5e56SDavid van Moolenbroek 	int l, k, j, i;
71*340f5e56SDavid van Moolenbroek 
72*340f5e56SDavid van Moolenbroek 	if (!isindex || !httpd->dir_indexing)
73*340f5e56SDavid van Moolenbroek 		return 0;
74*340f5e56SDavid van Moolenbroek 
75*340f5e56SDavid van Moolenbroek 	if (strlen(dirpath) <= strlen(httpd->index_html))
76*340f5e56SDavid van Moolenbroek 		dirpath = ".";
77*340f5e56SDavid van Moolenbroek 	else {
78*340f5e56SDavid van Moolenbroek 		file = bozostrdup(httpd, dirpath);
79*340f5e56SDavid van Moolenbroek 
80*340f5e56SDavid van Moolenbroek 		file[strlen(file) - strlen(httpd->index_html)] = '\0';
81*340f5e56SDavid van Moolenbroek 		dirpath = file;
82*340f5e56SDavid van Moolenbroek 	}
83*340f5e56SDavid van Moolenbroek 	debug((httpd, DEBUG_FAT, "bozo_dir_index: dirpath ``%s''", dirpath));
84*340f5e56SDavid van Moolenbroek 	if (stat(dirpath, &sb) < 0 ||
85*340f5e56SDavid van Moolenbroek 	    (dp = opendir(dirpath)) == NULL) {
86*340f5e56SDavid van Moolenbroek 		if (errno == EPERM)
87*340f5e56SDavid van Moolenbroek 			(void)bozo_http_error(httpd, 403, request,
88*340f5e56SDavid van Moolenbroek 			    "no permission to open directory");
89*340f5e56SDavid van Moolenbroek 		else if (errno == ENOENT)
90*340f5e56SDavid van Moolenbroek 			(void)bozo_http_error(httpd, 404, request, "no file");
91*340f5e56SDavid van Moolenbroek 		else
92*340f5e56SDavid van Moolenbroek 			(void)bozo_http_error(httpd, 500, request,
93*340f5e56SDavid van Moolenbroek 					"open directory");
94*340f5e56SDavid van Moolenbroek 		goto done;
95*340f5e56SDavid van Moolenbroek 		/* NOTREACHED */
96*340f5e56SDavid van Moolenbroek 	}
97*340f5e56SDavid van Moolenbroek 
98*340f5e56SDavid van Moolenbroek 	bozo_printf(httpd, "%s 200 OK\r\n", request->hr_proto);
99*340f5e56SDavid van Moolenbroek 
100*340f5e56SDavid van Moolenbroek 	if (request->hr_proto != httpd->consts.http_09) {
101*340f5e56SDavid van Moolenbroek 		bozo_print_header(request, NULL, "text/html", "");
102*340f5e56SDavid van Moolenbroek 		bozo_printf(httpd, "\r\n");
103*340f5e56SDavid van Moolenbroek 	}
104*340f5e56SDavid van Moolenbroek 	bozo_flush(httpd, stdout);
105*340f5e56SDavid van Moolenbroek 
106*340f5e56SDavid van Moolenbroek 	if (request->hr_method == HTTP_HEAD) {
107*340f5e56SDavid van Moolenbroek 		closedir(dp);
108*340f5e56SDavid van Moolenbroek 		goto done;
109*340f5e56SDavid van Moolenbroek 	}
110*340f5e56SDavid van Moolenbroek 
111*340f5e56SDavid van Moolenbroek 	bozo_printf(httpd,
112*340f5e56SDavid van Moolenbroek 		"<html><head><title>Index of %s</title></head>\r\n",
113*340f5e56SDavid van Moolenbroek 		request->hr_file);
114*340f5e56SDavid van Moolenbroek 	bozo_printf(httpd, "<body><h1>Index of %s</h1>\r\n",
115*340f5e56SDavid van Moolenbroek 		request->hr_file);
116*340f5e56SDavid van Moolenbroek 	bozo_printf(httpd, "<pre>\r\n");
117*340f5e56SDavid van Moolenbroek #define NAMELEN 40
118*340f5e56SDavid van Moolenbroek #define LMODLEN 19
119*340f5e56SDavid van Moolenbroek 	bozo_printf(httpd, "Name                                     "
120*340f5e56SDavid van Moolenbroek 	    "Last modified          "
121*340f5e56SDavid van Moolenbroek 	    "Size\n");
122*340f5e56SDavid van Moolenbroek 	bozo_printf(httpd, "</pre>");
123*340f5e56SDavid van Moolenbroek 	directory_hr(httpd);
124*340f5e56SDavid van Moolenbroek 	bozo_printf(httpd, "<pre>");
125*340f5e56SDavid van Moolenbroek 
126*340f5e56SDavid van Moolenbroek 	for (j = k = scandir(dirpath, &de, NULL, alphasort), deo = de;
127*340f5e56SDavid van Moolenbroek 	    j--; de++) {
128*340f5e56SDavid van Moolenbroek 		int nostat = 0;
129*340f5e56SDavid van Moolenbroek 		char *name = (*de)->d_name;
130*340f5e56SDavid van Moolenbroek 		char *urlname, *htmlname;
131*340f5e56SDavid van Moolenbroek 
132*340f5e56SDavid van Moolenbroek 		if (strcmp(name, ".") == 0 ||
133*340f5e56SDavid van Moolenbroek 		    (strcmp(name, "..") != 0 &&
134*340f5e56SDavid van Moolenbroek 		     httpd->hide_dots && name[0] == '.'))
135*340f5e56SDavid van Moolenbroek 			continue;
136*340f5e56SDavid van Moolenbroek 
137*340f5e56SDavid van Moolenbroek 		snprintf(buf, sizeof buf, "%s/%s", dirpath, name);
138*340f5e56SDavid van Moolenbroek 		if (stat(buf, &sb))
139*340f5e56SDavid van Moolenbroek 			nostat = 1;
140*340f5e56SDavid van Moolenbroek 
141*340f5e56SDavid van Moolenbroek 		l = 0;
142*340f5e56SDavid van Moolenbroek 
143*340f5e56SDavid van Moolenbroek 		urlname = bozo_escape_rfc3986(httpd, name);
144*340f5e56SDavid van Moolenbroek 		htmlname = bozo_escape_html(httpd, name);
145*340f5e56SDavid van Moolenbroek 		if (htmlname == NULL)
146*340f5e56SDavid van Moolenbroek 			htmlname = name;
147*340f5e56SDavid van Moolenbroek 		if (strcmp(name, "..") == 0) {
148*340f5e56SDavid van Moolenbroek 			bozo_printf(httpd, "<a href=\"../\">");
149*340f5e56SDavid van Moolenbroek 			l += bozo_printf(httpd, "Parent Directory");
150*340f5e56SDavid van Moolenbroek 		} else if (S_ISDIR(sb.st_mode)) {
151*340f5e56SDavid van Moolenbroek 			bozo_printf(httpd, "<a href=\"%s/\">", urlname);
152*340f5e56SDavid van Moolenbroek 			l += bozo_printf(httpd, "%s/", htmlname);
153*340f5e56SDavid van Moolenbroek 		} else if (strchr(name, ':') != NULL) {
154*340f5e56SDavid van Moolenbroek 			/* RFC 3986 4.2 */
155*340f5e56SDavid van Moolenbroek 			bozo_printf(httpd, "<a href=\"./%s\">", urlname);
156*340f5e56SDavid van Moolenbroek 			l += bozo_printf(httpd, "%s", htmlname);
157*340f5e56SDavid van Moolenbroek 		} else {
158*340f5e56SDavid van Moolenbroek 			bozo_printf(httpd, "<a href=\"%s\">", urlname);
159*340f5e56SDavid van Moolenbroek 			l += bozo_printf(httpd, "%s", htmlname);
160*340f5e56SDavid van Moolenbroek 		}
161*340f5e56SDavid van Moolenbroek 		if (htmlname != name)
162*340f5e56SDavid van Moolenbroek 			free(htmlname);
163*340f5e56SDavid van Moolenbroek 		bozo_printf(httpd, "</a>");
164*340f5e56SDavid van Moolenbroek 
165*340f5e56SDavid van Moolenbroek 		/* NAMELEN spaces */
166*340f5e56SDavid van Moolenbroek 		/*LINTED*/
167*340f5e56SDavid van Moolenbroek 		assert(/*CONSTCOND*/sizeof(spacebuf) > NAMELEN);
168*340f5e56SDavid van Moolenbroek 		i = (l < NAMELEN) ? (NAMELEN - l) : 0;
169*340f5e56SDavid van Moolenbroek 		i++;
170*340f5e56SDavid van Moolenbroek 		memset(spacebuf, ' ', (size_t)i);
171*340f5e56SDavid van Moolenbroek 		spacebuf[i] = '\0';
172*340f5e56SDavid van Moolenbroek 		bozo_printf(httpd, "%s", spacebuf);
173*340f5e56SDavid van Moolenbroek 		l += i;
174*340f5e56SDavid van Moolenbroek 
175*340f5e56SDavid van Moolenbroek 		if (nostat)
176*340f5e56SDavid van Moolenbroek 			bozo_printf(httpd, "?                         ?");
177*340f5e56SDavid van Moolenbroek 		else {
178*340f5e56SDavid van Moolenbroek 			tm = gmtime(&sb.st_mtime);
179*340f5e56SDavid van Moolenbroek 			strftime(buf, sizeof buf, "%d-%b-%Y %R", tm);
180*340f5e56SDavid van Moolenbroek 			l += bozo_printf(httpd, "%s", buf);
181*340f5e56SDavid van Moolenbroek 
182*340f5e56SDavid van Moolenbroek 			/* LMODLEN spaces */
183*340f5e56SDavid van Moolenbroek 			/*LINTED*/
184*340f5e56SDavid van Moolenbroek 			assert(/*CONSTCOND*/sizeof(spacebuf) > LMODLEN);
185*340f5e56SDavid van Moolenbroek 			i = (l < (LMODLEN+NAMELEN+1)) ?
186*340f5e56SDavid van Moolenbroek 				((LMODLEN+NAMELEN+1) - l) : 0;
187*340f5e56SDavid van Moolenbroek 			i++;
188*340f5e56SDavid van Moolenbroek 			memset(spacebuf, ' ', (size_t)i);
189*340f5e56SDavid van Moolenbroek 			spacebuf[i] = '\0';
190*340f5e56SDavid van Moolenbroek 			bozo_printf(httpd, "%s", spacebuf);
191*340f5e56SDavid van Moolenbroek 
192*340f5e56SDavid van Moolenbroek 			bozo_printf(httpd, "%12llukB",
193*340f5e56SDavid van Moolenbroek 				    (unsigned long long)sb.st_size >> 10);
194*340f5e56SDavid van Moolenbroek 		}
195*340f5e56SDavid van Moolenbroek 		bozo_printf(httpd, "\r\n");
196*340f5e56SDavid van Moolenbroek 	}
197*340f5e56SDavid van Moolenbroek 
198*340f5e56SDavid van Moolenbroek 	closedir(dp);
199*340f5e56SDavid van Moolenbroek 	while (k--)
200*340f5e56SDavid van Moolenbroek         	free(deo[k]);
201*340f5e56SDavid van Moolenbroek 	free(deo);
202*340f5e56SDavid van Moolenbroek 	bozo_printf(httpd, "</pre>");
203*340f5e56SDavid van Moolenbroek 	directory_hr(httpd);
204*340f5e56SDavid van Moolenbroek 	bozo_printf(httpd, "</body></html>\r\n\r\n");
205*340f5e56SDavid van Moolenbroek 	bozo_flush(httpd, stdout);
206*340f5e56SDavid van Moolenbroek 
207*340f5e56SDavid van Moolenbroek done:
208*340f5e56SDavid van Moolenbroek 	free(file);
209*340f5e56SDavid van Moolenbroek 	return 1;
210*340f5e56SDavid van Moolenbroek }
211*340f5e56SDavid van Moolenbroek #endif /* NO_DIRINDEX_SUPPORT */
212*340f5e56SDavid van Moolenbroek 
213