1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include "toys.h"
27
28char *rfc1123(char *buf, time_t t)
29{
30 strftime(buf, 64, "%a, %d %b %Y %T GMT", gmtime(&t));
31
32 return buf;
33}
34
35
36void header_time(int stat, char *str, char *more)
37{
38 char buf[64];
39
40 xprintf("HTTP/1.1 %d %s\r\nServer: toybox httpd/%s\r\nDate: %s\r\n%s"
41 "Connection: close\r\n\r\n", stat, str, TOYBOX_VERSION,
42 rfc1123(buf, time(0)), more ? : "");
43}
44
45void error_time(int stat, char *str)
46{
47 header_time(stat, str, 0);
48 xprintf("<html><head><title>%d %s</title></head>"
49 "<body><h3>%d %s</h3></body></html>", stat, str, stat, str);
50}
51
52
53char *mime(char *file)
54{
55 char *s = strrchr(file, '.'), *types[] = {
56 "asc\0text/plain", "bin\0application/octet-stream", "bmp\0image/bmp",
57 "cpio\0application/x-cpio", "css\0text/css", "doc\0application/msword",
58 "dtd\0text/xml", "dvi\0application/x-dvi", "gif\0image/gif",
59 "htm\0text/html", "html\0text/html", "jar\0applicat/x-java-archive",
60 "jpeg\0image/jpeg", "jpg\0image/jpeg", "js\0application/x-javascript",
61 "mp3\0audio/mpeg", "mp4\0video/mp4", "mpg\0video/mpeg",
62 "ogg\0application/ogg", "pbm\0image/x-portable-bitmap",
63 "pdf\0application/pdf", "png\0image/png",
64 "ppt\0application/vnd.ms-powerpoint", "ps\0application/postscript",
65 "rtf\0text/rtf", "sgml\0text/sgml", "svg\0image/svg+xml",
66 "tar\0application/x-tar", "tex\0application/x-tex", "tiff\0image/tiff",
67 "txt\0text/plain", "wav\0audio/x-wav", "xls\0application/vnd.ms-excel",
68 "xml\0tet/xml", "zip\0application/zip"
69 };
70 int i;
71
72 strcpy(toybuf, "text/plain");
73 if (s++) for (i = 0; i<ARRAY_LEN(types); i++) {
74 if (strcasecmp(s, types[i])) continue;
75 strcpy(toybuf, types[i]+strlen(types[i])+1);
76 break;
77 }
78 if (!strncmp(toybuf, "text/", 5)) strcat(toybuf, "; charset=UTF-8");
79
80 return toybuf;
81}
82
83static int isunder(char *file, char *dir)
84{
85 char *s1 = xabspath(dir, ABS_FILE), *s2 = xabspath(file, 0), *ss = s2;
86 int rc = s1 && s2 && strstart(&ss, s1) && (!*ss || *ss=='/' || ss[-1]=='/');
87
88 free(s2);
89 free(s1);
90
91 return rc;
92}
93
94
95void handle(int infd, int outfd)
96{
97 FILE *fp = fdopen(infd, "r");
98 char *s = xgetline(fp), *ss, *esc, *path, *word[3];
99 int i, fd;
100
101
102 for (i = 0, ss = s;;) {
103 word[i++] = ss;
104 while (*ss && !strchr(" \r\n", *ss)) ss++;
105 while (*ss && strchr(" \r\n", *ss)) *(ss++) = 0;
106 if (i==3) break;
107 if (!*ss) return header_time(400, "Bad Request", 0);
108 }
109
110
111 while ((ss = xgetline(fp))) {
112 i = *chomp(ss);
113
114
115
116
117
118
119
120 free(ss);
121 if (!i) break;
122 }
123
124 if (!strcasecmp(word[0], "get")) {
125 struct stat st;
126 if (*(ss = word[1])!='/') error_time(400, "Bad Request");
127 while (*ss=='/') ss++;
128 if (!*ss) ss = ".";
129 else unescape_url(ss);
130
131
132 if (!isunder(ss, ".") || stat(ss, &st)) error_time(404, "Not Found");
133 else if (-1 == (fd = open(ss, O_RDONLY))) error_time(403, "Forbidden");
134 else if (!S_ISDIR(st.st_mode)) {
135 char buf[64];
136file:
137 header_time(200, "Ok", ss = xmprintf("Content-Type: %s\r\n"
138 "Content-Length: %lld\r\nLast-Modified: %s\r\n",
139 mime(ss), (long long)st.st_size, rfc1123(buf, st.st_mtime)));
140 free(ss);
141 xsendfile(fd, outfd);
142 } else if (ss[strlen(ss)-1]!='/' && strcmp(ss, ".")) {
143 header_time(302, "Found", path = xmprintf("Location: %s/\r\n", word[1]));
144 free(path);
145 } else {
146 DIR *dd;
147 struct dirent *dir;
148
149
150 path = ss;
151 ss = "index.html";
152 path = xmprintf("%s%s", path, ss);
153 if (!stat(path, &st) || !S_ISREG(st.st_mode)) i = -1;
154 else if (-1 == (i = open(path, O_RDONLY))) error_time(403, "Forbidden");
155 free(path);
156 if (i != -1) {
157 close(fd);
158 fd = i;
159
160 goto file;
161 }
162
163
164 header_time(200, "Ok", "Content-Type: text/html\r\n");
165 dprintf(outfd, "<html><head><title>Index of %s</title></head>\n"
166 "<body><h3>Index of %s</h3></body>\n", word[1], word[1]);
167 for (dd = fdopendir(fd); (dir = readdir(dd));) {
168 esc = escape_url(dir->d_name, "<>&\"");
169 dprintf(outfd, "<a href=\"%s\">%s</a><br />\n", esc, esc);
170 free(esc);
171 }
172 dprintf(outfd, "</body></html>\n");
173 }
174 } else error_time(501, "Not Implemented");
175 free(s);
176}
177
178void httpd_main(void)
179{
180 if (toys.optc && chdir(*toys.optargs))
181 return error_time(500, "Internal Error");
182
183 handle(0, 1);
184}
185