]> code.citadel.org Git - citadel.git/blob - webcit/static.c
Merge branch 'stable-78x' of ssh://git.citadel.org/appl/gitroot/citadel into stable-78x
[citadel.git] / webcit / static.c
1 /*
2  * $Id$
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 #include <stddef.h>
17
18
19 #include "webcit.h"
20 #include "webserver.h"
21
22
23 HashList *StaticFilemappings[4] = {NULL, NULL, NULL, NULL};
24 /*
25                 {
26                         lprintf(9, "Suspicious request. Ignoring.");
27                         hprintf("HTTP/1.1 404 Security check failed\r\n");
28                         hprintf("Content-Type: text/plain\r\n\r\n");
29                         wc_printf("You have sent a malformed or invalid request.\r\n");
30                         end_burst();
31                 }
32 */
33 /*
34  * dump out static pages from disk
35  */
36 void output_static(const char *what)
37 {
38         int fd;
39         struct stat statbuf;
40         off_t bytes;
41         const char *content_type;
42         int len;
43         const char *Err;
44
45         fd = open(what, O_RDONLY);
46         if (fd <= 0) {
47                 lprintf(9, "output_static('%s') [%s]  -- NOT FOUND --\n", what, ChrPtr(WC->Hdr->this_page));
48                 hprintf("HTTP/1.1 404 %s\r\n", strerror(errno));
49                 hprintf("Content-Type: text/plain\r\n");
50                 begin_burst();
51                 wc_printf("Cannot open %s: %s\r\n", what, strerror(errno));
52                 end_burst();
53         } else {
54                 len = strlen (what);
55                 content_type = GuessMimeByFilename(what, len);
56
57                 if (fstat(fd, &statbuf) == -1) {
58                         lprintf(9, "output_static('%s')  -- FSTAT FAILED --\n", what);
59                         hprintf("HTTP/1.1 404 %s\r\n", strerror(errno));
60                         hprintf("Content-Type: text/plain\r\n");
61                         begin_burst();
62                         wc_printf("Cannot fstat %s: %s\n", what, strerror(errno));
63                         end_burst();
64                         return;
65                 }
66
67                 bytes = statbuf.st_size;
68
69                 if (StrBufReadBLOB(WC->WBuf, &fd, 1, bytes, &Err) < 0)
70                 {
71                         if (fd > 0) close(fd);
72                         lprintf(9, "output_static('%s')  -- FREAD FAILED (%s) --\n", what, strerror(errno));
73                                 hprintf("HTTP/1.1 500 internal server error \r\n");
74                                 hprintf("Content-Type: text/plain\r\n");
75                                 end_burst();
76                                 return;
77                 }
78
79
80                 close(fd);
81 #ifndef TECH_PREVIEW
82                 lprintf(9, "output_static('%s')  %s\n", what, content_type);
83 #endif
84                 http_transmit_thing(content_type, 2);
85         }
86         if (yesbstr("force_close_session")) {
87                 end_webcit_session();
88         }
89 }
90
91
92 int LoadStaticDir(const char *DirName, HashList *DirList, const char *RelDir)
93 {
94         char dirname[PATH_MAX];
95         char reldir[PATH_MAX];
96         StrBuf *FileName = NULL;
97         StrBuf *Dir = NULL;
98         StrBuf *WebDir = NULL;
99         StrBuf *OneWebName = NULL;
100         DIR *filedir = NULL;
101         struct dirent *d;
102         struct dirent *filedir_entry;
103         int d_type = 0;
104         int d_namelen;
105         int istoplevel;
106                 
107         filedir = opendir (DirName);
108         if (filedir == NULL) {
109                 return 0;
110         }
111
112         d = (struct dirent *)malloc(offsetof(struct dirent, d_name) + PATH_MAX + 1);
113         if (d == NULL) {
114                 return 0;
115         }
116
117         Dir = NewStrBufPlain(DirName, -1);
118         WebDir = NewStrBufPlain(RelDir, -1);
119         istoplevel = IsEmptyStr(RelDir);
120         OneWebName = NewStrBuf();
121
122         while ((readdir_r(filedir, d, &filedir_entry) == 0) &&
123                (filedir_entry != NULL))
124         {
125 #ifdef _DIRENT_HAVE_D_NAMELEN
126                 d_namelen = filedir_entry->d_namelen;
127                 d_type = filedir_entry->d_type;
128 #else
129
130 #ifndef DT_UNKNOWN
131 #define DT_UNKNOWN     0
132 #define DT_DIR         4
133 #define DT_REG         8
134 #define DT_LNK         10
135
136 #define IFTODT(mode)   (((mode) & 0170000) >> 12)
137 #define DTTOIF(dirtype)        ((dirtype) << 12)
138 #endif
139                 d_namelen = strlen(filedir_entry->d_name);
140                 d_type = DT_UNKNOWN;
141 #endif
142                 if ((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~')
143                         continue; /* Ignore backup files... */
144
145                 if ((d_namelen == 1) && 
146                     (filedir_entry->d_name[0] == '.'))
147                         continue;
148
149                 if ((d_namelen == 2) && 
150                     (filedir_entry->d_name[0] == '.') &&
151                     (filedir_entry->d_name[1] == '.'))
152                         continue;
153
154                 if (d_type == DT_UNKNOWN) {
155                         struct stat s;
156                         char path[PATH_MAX];
157                         snprintf(path, PATH_MAX, "%s/%s", 
158                                 DirName, filedir_entry->d_name);
159                         if (stat(path, &s) == 0) {
160                                 d_type = IFTODT(s.st_mode);
161                         }
162                 }
163
164                 switch (d_type)
165                 {
166                 case DT_DIR:
167                         /* Skip directories we are not interested in... */
168                         if ((strcmp(filedir_entry->d_name, ".svn") == 0) ||
169                             (strcmp(filedir_entry->d_name, "t") == 0))
170                                 break;
171                         snprintf(dirname, PATH_MAX, "%s/%s/", 
172                                  DirName, filedir_entry->d_name);
173                         if (istoplevel)
174                                 snprintf(reldir, PATH_MAX, "%s/", 
175                                          filedir_entry->d_name);
176                         else
177                                 snprintf(reldir, PATH_MAX, "%s/%s/", 
178                                          RelDir, filedir_entry->d_name);
179                         StripSlashes(dirname, 1);
180                         StripSlashes(reldir, 1);
181                         LoadStaticDir(dirname, DirList, reldir);                                 
182                         break;
183                 case DT_LNK: /* TODO: check whether its a file or a directory */
184                 case DT_REG:
185                         FileName = NewStrBufDup(Dir);
186                         if (ChrPtr(FileName) [ StrLength(FileName) - 1] != '/')
187                                 StrBufAppendBufPlain(FileName, "/", 1, 0);
188                         StrBufAppendBufPlain(FileName, filedir_entry->d_name, d_namelen, 0);
189
190                         FlushStrBuf(OneWebName);
191                         StrBufAppendBuf(OneWebName, WebDir, 0);
192                         if ((StrLength(OneWebName) != 0) && 
193                             (ChrPtr(OneWebName) [ StrLength(OneWebName) - 1] != '/'))
194                                 StrBufAppendBufPlain(OneWebName, "/", 1, 0);
195                         StrBufAppendBufPlain(OneWebName, filedir_entry->d_name, d_namelen, 0);
196
197                         Put(DirList, SKEY(OneWebName), FileName, HFreeStrBuf);
198                         /* lprintf(9, "[%s | %s]\n", ChrPtr(OneWebName), ChrPtr(FileName)); */
199                         break;
200                 default:
201                         break;
202                 }
203
204
205         }
206         free(d);
207         closedir(filedir);
208         FreeStrBuf(&Dir);
209         FreeStrBuf(&WebDir);
210         FreeStrBuf(&OneWebName);
211         return 1;
212 }
213
214
215 void output_flat_static(void)
216 {
217         wcsession *WCC = WC;
218         void *vFile;
219         StrBuf *File;
220
221         if (GetHash(StaticFilemappings[0], SKEY(WCC->Hdr->HR.Handler->Name), &vFile) &&
222             (vFile != NULL))
223         {
224                 File = (StrBuf*) vFile;
225                 output_static(ChrPtr(File));
226         }
227 }
228
229 extern void do_404(void);
230
231 void output_static_safe(HashList *DirList)
232 {
233         wcsession *WCC = WC;
234         void *vFile;
235         StrBuf *File;
236
237         if (GetHash(DirList, SKEY(WCC->Hdr->HR.ReqLine), &vFile) &&
238             (vFile != NULL))
239         {
240                 File = (StrBuf*) vFile;
241                 output_static(ChrPtr(File));
242         }
243         else {
244                 lprintf(1, "output_static_safe() file %s not found. \n", 
245                         ChrPtr(WCC->Hdr->HR.ReqLine));
246 ///TODO: detect image & output blank image
247                 do_404();
248         }
249 }
250 void output_static_0(void)
251 {
252         output_static_safe(StaticFilemappings[0]);
253 }
254 void output_static_1(void)
255 {
256         output_static_safe(StaticFilemappings[1]);
257 }
258 void output_static_2(void)
259 {
260         output_static_safe(StaticFilemappings[2]);
261 }
262 void output_static_3(void)
263 {
264         output_static_safe(StaticFilemappings[3]);
265 }
266
267 void 
268 ServerStartModule_STATIC
269 (void)
270 {
271         StaticFilemappings[0] = NewHash(1, NULL);
272         StaticFilemappings[1] = NewHash(1, NULL);
273         StaticFilemappings[2] = NewHash(1, NULL);
274         StaticFilemappings[3] = NewHash(1, NULL);
275 }
276 void 
277 ServerShutdownModule_STATIC
278 (void)
279 {
280         DeleteHash(&StaticFilemappings[0]);
281         DeleteHash(&StaticFilemappings[1]);
282         DeleteHash(&StaticFilemappings[2]);
283         DeleteHash(&StaticFilemappings[3]);
284 }
285
286
287 void 
288 InitModule_STATIC
289 (void)
290 {
291         LoadStaticDir(static_dirs[0], StaticFilemappings[0], "");
292         LoadStaticDir(static_dirs[1], StaticFilemappings[1], "");
293         LoadStaticDir(static_dirs[2], StaticFilemappings[2], "");
294         LoadStaticDir(static_dirs[3], StaticFilemappings[3], "");
295
296         WebcitAddUrlHandler(HKEY("robots.txt"), "", 0, output_flat_static, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
297         WebcitAddUrlHandler(HKEY("favicon.ico"), "", 0, output_flat_static, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
298         WebcitAddUrlHandler(HKEY("static"), "", 0, output_static_0, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
299         WebcitAddUrlHandler(HKEY("static.local"), "", 0, output_static_1, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
300         WebcitAddUrlHandler(HKEY("tinymce"), "", 0, output_static_2, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
301         WebcitAddUrlHandler(HKEY("tiny_mce"), "", 0, output_static_2, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
302 }