* re-create static support; we now safe us from ..'ers by just looking up the filenam...
[citadel.git] / webcit / static.c
1 /*
2  * $Id: webcit.c 7459 2009-05-17 08:34:33Z dothebart $
3  *
4  * This is the main transaction loop of the web service.  It maintains a
5  * persistent session to the Citadel server, handling HTTP WebCit requests as
6  * they arrive and presenting a user interface.
7  */
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <dirent.h>
11 #include <errno.h>
12
13 #include <unistd.h>
14 #include <stdio.h>
15 #include <stdarg.h>
16
17 #include "webcit.h"
18 #include "webserver.h"
19
20
21 HashList *StaticFilemappings[4] = {NULL, NULL, NULL, NULL};
22
23
24 /*
25   for ( a = 0; a < 9; ++a)
26   {
27   extract_token(index[a], ChrPtr(ReqLine), a + 1, '/', sizes[a]);
28   if (strstr(index[a], "?")) *strstr(index[a], "?") = 0;
29   if (strstr(index[a], "&")) *strstr(index[a], "&") = 0;
30   if (strstr(index[a], " ")) *strstr(index[a], " ") = 0;
31   if ((index[a][0] == '.') && (index[a][1] == '.'))
32   nBackDots++;
33   if (index[a][0] == '\0')
34   nEmpty++;
35   }
36 */
37
38 /* TODO: staticdata
39 {
40
41
42         /** Figure out the action * /
43         index[0] = action;
44         sizes[0] = sizeof action;
45         for (a=1; a<9; a++)
46         {
47                 index[a] = arg[a-1];
48                 sizes[a] = sizeof arg[a-1];
49         }
50         nBackDots = 0;
51         nEmpty = 0;
52
53
54         /* Static content can be sent without connecting to Citadel. * /
55         is_static = 0;
56         for (a=0; a<ndirs && ! is_static; ++a) {
57                 if (!strcasecmp(action, (char*)static_content_dirs[a])) { /* map web to disk location * /
58                         is_static = 1;
59                         n_static = a;
60                 }
61         }
62         if (is_static) {
63                 if (nBackDots < 2)
64                 {
65                         snprintf(buf, sizeof buf, "%s/%s/%s/%s/%s/%s/%s/%s",
66                                  static_dirs[n_static], 
67                                  index[1], index[2], index[3], index[4], index[5], index[6], index[7]);
68                         for (a=0; a<8; ++a) {
69                                 if (buf[strlen(buf)-1] == '/') {
70                                         buf[strlen(buf)-1] = 0;
71                                 }
72                         }
73                         for (a = 0; a < strlen(buf); ++a) {
74                                 if (isspace(buf[a])) {
75                                         buf[a] = 0;
76                                 }
77                         }
78                         output_static(buf);
79                 }
80                 else 
81                 {
82                         lprintf(9, "Suspicious request. Ignoring.");
83                         hprintf("HTTP/1.1 404 Security check failed\r\n");
84                         hprintf("Content-Type: text/plain\r\n\r\n");
85                         wprintf("You have sent a malformed or invalid request.\r\n");
86                         end_burst();
87                 }
88                 goto SKIP_ALL_THIS_CRAP;        /* Don't try to connect * /
89         }
90         }*/
91
92
93 /*
94  * dump out static pages from disk
95  */
96 void output_static(const char *what)
97 {
98         int fd;
99         struct stat statbuf;
100         off_t bytes;
101         off_t count = 0;
102         const char *content_type;
103         int len;
104         const char *Err;
105
106         fd = open(what, O_RDONLY);
107         if (fd <= 0) {
108                 lprintf(9, "output_static('%s')  -- NOT FOUND --\n", what);
109                 hprintf("HTTP/1.1 404 %s\r\n", strerror(errno));
110                 hprintf("Content-Type: text/plain\r\n");
111                 wprintf("Cannot open %s: %s\r\n", what, strerror(errno));
112                 end_burst();
113         } else {
114                 len = strlen (what);
115                 content_type = GuessMimeByFilename(what, len);
116
117                 if (fstat(fd, &statbuf) == -1) {
118                         lprintf(9, "output_static('%s')  -- FSTAT FAILED --\n", what);
119                         hprintf("HTTP/1.1 404 %s\r\n", strerror(errno));
120                         hprintf("Content-Type: text/plain\r\n");
121                         wprintf("Cannot fstat %s: %s\n", what, strerror(errno));
122                         end_burst();
123                         return;
124                 }
125
126                 count = 0;
127                 bytes = statbuf.st_size;
128
129                 if (StrBufReadBLOB(WC->WBuf, &fd, 1, bytes, &Err) < 0)
130                 {
131                         if (fd > 0) close(fd);
132                         lprintf(9, "output_static('%s')  -- FREAD FAILED (%s) --\n", what, strerror(errno));
133                                 hprintf("HTTP/1.1 500 internal server error \r\n");
134                                 hprintf("Content-Type: text/plain\r\n");
135                                 end_burst();
136                                 return;
137                 }
138
139
140                 close(fd);
141 #ifndef TECH_PREVIEW
142                 lprintf(9, "output_static('%s')  %s\n", what, content_type);
143 #endif
144                 http_transmit_thing(content_type, 1);
145         }
146         if (yesbstr("force_close_session")) {
147                 end_webcit_session();
148         }
149 }
150
151         /* TODO: integrate this into the static startup logic
152
153          * While we're at it, gracefully handle requests for the
154          * robots.txt and favicon.ico files.
155          * /
156         if ((StrLength(ReqLine) >= 11) &&
157             !strncasecmp(ChrPtr(ReqLine), "/robots.txt", 11)) {
158                 StrBufPlain(ReqLine, 
159                             HKEY("/static/robots.txt"
160                                  "?force_close_session=yes HTTP/1.1"));
161                 Hdr.eReqType = eGET;
162         }
163         else if ((StrLength(ReqLine) >= 11) &&
164                  !strncasecmp(ChrPtr(ReqLine), "/favicon.ico", 12)) {
165                 StrBufPlain(ReqLine, HKEY("/static/favicon.ico"));
166                 Hdr.eReqType = eGET;
167         }
168
169 */
170
171
172
173
174 int LoadStaticDir(const char *DirName, HashList *DirList, const char *RelDir)
175 {
176         char dirname[PATH_MAX];
177         char reldir[PATH_MAX];
178         StrBuf *FileName;
179         StrBuf *Tag;
180         StrBuf *Dir;
181         StrBuf *WebDir;
182         StrBuf *OneWebName;
183         DIR *filedir = NULL;
184         struct dirent d;
185         struct dirent *filedir_entry;
186         int d_namelen;
187         int d_without_ext;
188                 
189         Dir = NewStrBufPlain(DirName, -1);
190         WebDir = NewStrBufPlain(RelDir, -1);
191         OneWebName = NewStrBuf();
192         filedir = opendir (DirName);
193         if (filedir == NULL) {
194                 FreeStrBuf(&Dir);
195                 return 0;
196         }
197
198         FileName = NewStrBuf();
199         Tag = NewStrBuf();
200         while ((readdir_r(filedir, &d, &filedir_entry) == 0) &&
201                (filedir_entry != NULL))
202         {
203                 char *PStart;
204 #ifdef _DIRENT_HAVE_D_NAMELEN
205                 d_namelen = filedir_entry->d_namelen;
206 #else
207                 d_namelen = strlen(filedir_entry->d_name);
208 #endif
209                 d_without_ext = d_namelen;
210
211                 if ((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~')
212                         continue; /* Ignore backup files... */
213
214                 if ((d_namelen == 1) && 
215                     (filedir_entry->d_name[0] == '.'))
216                         continue;
217
218                 if ((d_namelen == 2) && 
219                     (filedir_entry->d_name[0] == '.') &&
220                     (filedir_entry->d_name[1] == '.'))
221                         continue;
222
223                 switch (filedir_entry->d_type)
224                 {
225                 case DT_DIR:
226                         /* Skip directories we are not interested in... */
227                         if ((strcmp(filedir_entry->d_name, ".svn") == 0) ||
228                             (strcmp(filedir_entry->d_name, "t") == 0))
229                                 break;
230                         snprintf(dirname, PATH_MAX, "%s/%s", 
231                                  DirName, filedir_entry->d_name);
232                         snprintf(reldir, PATH_MAX, "%s/%s", 
233                                  RelDir, filedir_entry->d_name);
234                         LoadStaticDir(dirname, DirList, reldir);                                 
235                         break;
236                 case DT_LNK: /* TODO: check whether its a file or a directory */
237                 case DT_REG:
238                         PStart = filedir_entry->d_name;
239                         FileName = NewStrBufDup(Dir);
240                         if (ChrPtr(FileName) [ StrLength(FileName) - 1] != '/')
241                                 StrBufAppendBufPlain(FileName, "/", 1, 0);
242                         StrBufAppendBufPlain(FileName, filedir_entry->d_name, d_namelen, 0);
243
244                         FlushStrBuf(OneWebName);
245                         StrBufAppendBuf(OneWebName, WebDir, 0);
246                         if ((StrLength(OneWebName) != 0) && 
247                             (ChrPtr(OneWebName) [ StrLength(OneWebName)] != '/'))
248                                 StrBufAppendBufPlain(OneWebName, "/", 1, 0);
249                         StrBufAppendBufPlain(OneWebName, filedir_entry->d_name, d_namelen, 0);
250
251                         Put(DirList, SKEY(OneWebName), FileName, HFreeStrBuf);
252                         printf("[%s | %s]  \n", ChrPtr(OneWebName), ChrPtr(FileName));
253                         break;
254                 default:
255                         break;
256                 }
257
258
259         }
260         closedir(filedir);
261         FreeStrBuf(&FileName);
262         FreeStrBuf(&Tag);
263         FreeStrBuf(&Dir);
264         FreeStrBuf(&OneWebName);
265         return 1;
266 }
267
268
269 void output_static_safe(HashList *DirList)
270 {
271         wcsession *WCC = WC;
272         void *vFile;
273         StrBuf *File;
274
275         if (GetHash(DirList, SKEY(WCC->Hdr->ReqLine), &vFile) &&
276             (vFile != NULL))
277         {
278                 File = (StrBuf*) vFile;
279                 output_static(ChrPtr(vFile));
280         }
281         else {
282 ///TODO: detect image & output blank image
283         }
284 }
285 void output_static_0(void)
286 {
287         output_static_safe(StaticFilemappings[0]);
288 }
289 void output_static_1(void)
290 {
291         output_static_safe(StaticFilemappings[1]);
292 }
293 void output_static_2(void)
294 {
295         output_static_safe(StaticFilemappings[2]);
296 }
297 void output_static_3(void)
298 {
299         output_static_safe(StaticFilemappings[3]);
300 }
301
302 void 
303 ServerStartModule_STATIC
304 (void)
305 {
306         StaticFilemappings[0] = NewHash(1, NULL);
307         StaticFilemappings[1] = NewHash(1, NULL);
308         StaticFilemappings[2] = NewHash(1, NULL);
309         StaticFilemappings[3] = NewHash(1, NULL);
310 }
311 void 
312 ServerShutdownModule_STATIC
313 (void)
314 {
315         DeleteHash(&StaticFilemappings[0]);
316         DeleteHash(&StaticFilemappings[1]);
317         DeleteHash(&StaticFilemappings[2]);
318         DeleteHash(&StaticFilemappings[3]);
319 }
320
321
322 void 
323 InitModule_STATIC
324 (void)
325 {
326         LoadStaticDir(static_dirs[0], StaticFilemappings[0], "");
327         LoadStaticDir(static_dirs[1], StaticFilemappings[1], "");
328         LoadStaticDir(static_dirs[2], StaticFilemappings[2], "");
329         LoadStaticDir(static_dirs[3], StaticFilemappings[3], "");
330
331         WebcitAddUrlHandler(HKEY("robots.txt"), output_static_0, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC);
332         WebcitAddUrlHandler(HKEY("favicon.ico"), output_static_0, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC);
333         WebcitAddUrlHandler(HKEY("static"), output_static_0, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC);
334         WebcitAddUrlHandler(HKEY("static.local"), output_static_1, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC);
335         WebcitAddUrlHandler(HKEY("tinymce"), output_static_2, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC);
336
337
338 }