2 * This is the main transaction loop of the web service. It maintains a
3 * persistent session to the Citadel server, handling HTTP WebCit requests as
4 * they arrive and presenting a user interface.
18 #include "webserver.h"
20 unsigned char OnePixelGif[37] = {
59 HashList *StaticFilemappings[4] = {NULL, NULL, NULL, NULL};
62 syslog(9, "Suspicious request. Ignoring.");
63 hprintf("HTTP/1.1 404 Security check failed\r\n");
64 hprintf("Content-Type: text/plain\r\n\r\n");
65 wc_printf("You have sent a malformed or invalid request.\r\n");
71 void output_error_pic(const char *ErrMsg1, const char *ErrMsg2)
73 hprintf("HTTP/1.1 200 %s\r\n", ErrMsg1);
74 hprintf("Content-Type: image/gif\r\n");
75 hprintf("x-webcit-errormessage: %s\r\n", ErrMsg2);
77 StrBufPlain(WC->WBuf, (const char *)OnePixelGif, sizeof(OnePixelGif));
82 * dump out static pages from disk
84 void output_static(const char *what)
89 const char *content_type;
94 content_type = GuessMimeByFilename(what, len);
95 fd = open(what, O_RDONLY);
97 syslog(9, "output_static('%s') [%s] -- NOT FOUND --\n", what, ChrPtr(WC->Hdr->this_page));
98 if (strstr(content_type, "image/") != NULL)
100 output_error_pic("the file you requsted is gone.", strerror(errno));
104 hprintf("HTTP/1.1 404 %s\r\n", strerror(errno));
105 hprintf("Content-Type: text/plain\r\n");
107 wc_printf("Cannot open %s: %s\r\n", what, strerror(errno));
111 if (fstat(fd, &statbuf) == -1) {
112 syslog(9, "output_static('%s') -- FSTAT FAILED --\n", what);
113 if (strstr(content_type, "image/") != NULL)
115 output_error_pic("Stat failed!", strerror(errno));
119 hprintf("HTTP/1.1 404 %s\r\n", strerror(errno));
120 hprintf("Content-Type: text/plain\r\n");
122 wc_printf("Cannot fstat %s: %s\n", what, strerror(errno));
125 if (fd > 0) close(fd);
129 bytes = statbuf.st_size;
131 if (StrBufReadBLOB(WC->WBuf, &fd, 1, bytes, &Err) < 0)
133 if (fd > 0) close(fd);
134 syslog(9, "output_static('%s') -- FREAD FAILED (%s) --\n", what, strerror(errno));
135 hprintf("HTTP/1.1 500 internal server error \r\n");
136 hprintf("Content-Type: text/plain\r\n");
143 http_transmit_thing(content_type, 2);
145 if (yesbstr("force_close_session")) {
146 end_webcit_session();
151 int LoadStaticDir(const char *DirName, HashList *DirList, const char *RelDir)
153 char dirname[PATH_MAX];
154 char reldir[PATH_MAX];
155 StrBuf *FileName = NULL;
157 StrBuf *WebDir = NULL;
158 StrBuf *OneWebName = NULL;
161 struct dirent *filedir_entry;
166 filedir = opendir (DirName);
167 if (filedir == NULL) {
171 d = (struct dirent *)malloc(offsetof(struct dirent, d_name) + PATH_MAX + 1);
177 Dir = NewStrBufPlain(DirName, -1);
178 WebDir = NewStrBufPlain(RelDir, -1);
179 istoplevel = IsEmptyStr(RelDir);
180 OneWebName = NewStrBuf();
182 while ((readdir_r(filedir, d, &filedir_entry) == 0) &&
183 (filedir_entry != NULL))
185 #ifdef _DIRENT_HAVE_D_NAMLEN
186 d_namelen = filedir_entry->d_namelen;
189 d_namelen = strlen(filedir_entry->d_name);
192 #ifdef _DIRENT_HAVE_D_TYPE
193 d_type = filedir_entry->d_type;
202 #define IFTODT(mode) (((mode) & 0170000) >> 12)
203 #define DTTOIF(dirtype) ((dirtype) << 12)
207 if ((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~')
208 continue; /* Ignore backup files... */
210 if ((d_namelen == 1) &&
211 (filedir_entry->d_name[0] == '.'))
214 if ((d_namelen == 2) &&
215 (filedir_entry->d_name[0] == '.') &&
216 (filedir_entry->d_name[1] == '.'))
219 if (d_type == DT_UNKNOWN) {
222 snprintf(path, PATH_MAX, "%s/%s",
223 DirName, filedir_entry->d_name);
224 if (lstat(path, &s) == 0) {
225 d_type = IFTODT(s.st_mode);
232 /* Skip directories we are not interested in... */
233 if ((strcmp(filedir_entry->d_name, ".svn") == 0) ||
234 (strcmp(filedir_entry->d_name, "t") == 0))
236 snprintf(dirname, PATH_MAX, "%s/%s/",
237 DirName, filedir_entry->d_name);
239 snprintf(reldir, PATH_MAX, "%s/",
240 filedir_entry->d_name);
242 snprintf(reldir, PATH_MAX, "%s/%s/",
243 RelDir, filedir_entry->d_name);
244 StripSlashes(dirname, 1);
245 StripSlashes(reldir, 1);
246 LoadStaticDir(dirname, DirList, reldir);
248 case DT_LNK: /* TODO: check whether its a file or a directory */
250 FileName = NewStrBufDup(Dir);
251 if (ChrPtr(FileName) [ StrLength(FileName) - 1] != '/')
252 StrBufAppendBufPlain(FileName, "/", 1, 0);
253 StrBufAppendBufPlain(FileName, filedir_entry->d_name, d_namelen, 0);
255 FlushStrBuf(OneWebName);
256 StrBufAppendBuf(OneWebName, WebDir, 0);
257 if ((StrLength(OneWebName) != 0) &&
258 (ChrPtr(OneWebName) [ StrLength(OneWebName) - 1] != '/'))
259 StrBufAppendBufPlain(OneWebName, "/", 1, 0);
260 StrBufAppendBufPlain(OneWebName, filedir_entry->d_name, d_namelen, 0);
262 Put(DirList, SKEY(OneWebName), FileName, HFreeStrBuf);
263 /* syslog(9, "[%s | %s]\n", ChrPtr(OneWebName), ChrPtr(FileName)); */
275 FreeStrBuf(&OneWebName);
280 void output_flat_static(void)
286 if (WCC->Hdr->HR.Handler == NULL)
288 if (GetHash(StaticFilemappings[0], SKEY(WCC->Hdr->HR.Handler->Name), &vFile) &&
291 File = (StrBuf*) vFile;
292 output_static(ChrPtr(File));
296 void output_static_safe(HashList *DirList)
301 const char *MimeType;
303 if (GetHash(DirList, SKEY(WCC->Hdr->HR.ReqLine), &vFile) &&
306 File = (StrBuf*) vFile;
307 output_static(ChrPtr(File));
310 syslog(1, "output_static_safe() file %s not found. \n",
311 ChrPtr(WCC->Hdr->HR.ReqLine));
312 MimeType = GuessMimeByFilename(SKEY(WCC->Hdr->HR.ReqLine));
313 if (strstr(MimeType, "image/") != NULL)
315 output_error_pic("the file you requested isn't known to our cache", "maybe reload webcit?");
323 void output_static_0(void)
325 output_static_safe(StaticFilemappings[0]);
327 void output_static_1(void)
329 output_static_safe(StaticFilemappings[1]);
331 void output_static_2(void)
333 output_static_safe(StaticFilemappings[2]);
335 void output_static_3(void)
337 output_static_safe(StaticFilemappings[3]);
344 void robots_txt(void) {
345 output_headers(0, 0, 0, 0, 0, 0);
347 hprintf("Content-type: text/plain\r\n"
349 "Connection: close\r\n",
353 wc_printf("User-agent: *\r\n"
354 "Disallow: /printmsg\r\n"
355 "Disallow: /msgheaders\r\n"
356 "Disallow: /groupdav\r\n"
357 "Disallow: /do_template\r\n"
358 "Disallow: /static\r\n"
359 "Disallow: /display_page\r\n"
360 "Disallow: /readnew\r\n"
361 "Disallow: /display_enter\r\n"
362 "Disallow: /skip\r\n"
363 "Disallow: /ungoto\r\n"
364 "Sitemap: %s/sitemap.xml\r\n"
375 ServerStartModule_STATIC
378 StaticFilemappings[0] = NewHash(1, NULL);
379 StaticFilemappings[1] = NewHash(1, NULL);
380 StaticFilemappings[2] = NewHash(1, NULL);
381 StaticFilemappings[3] = NewHash(1, NULL);
384 ServerShutdownModule_STATIC
387 DeleteHash(&StaticFilemappings[0]);
388 DeleteHash(&StaticFilemappings[1]);
389 DeleteHash(&StaticFilemappings[2]);
390 DeleteHash(&StaticFilemappings[3]);
398 LoadStaticDir(static_dirs[0], StaticFilemappings[0], "");
399 LoadStaticDir(static_dirs[1], StaticFilemappings[1], "");
400 LoadStaticDir(static_dirs[2], StaticFilemappings[2], "");
401 LoadStaticDir(static_dirs[3], StaticFilemappings[3], "");
403 WebcitAddUrlHandler(HKEY("robots.txt"), "", 0, robots_txt, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
404 WebcitAddUrlHandler(HKEY("favicon.ico"), "", 0, output_flat_static, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
405 WebcitAddUrlHandler(HKEY("static"), "", 0, output_static_0, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
406 WebcitAddUrlHandler(HKEY("static.local"), "", 0, output_static_1, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
407 WebcitAddUrlHandler(HKEY("tinymce"), "", 0, output_static_2, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
408 WebcitAddUrlHandler(HKEY("tiny_mce"), "", 0, output_static_2, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);