Bug Summary

File:src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/lib/abyss/src/handler.c
Location:line 310, column 13
Description:Value stored to 'k' is never read

Annotated Source Code

1/*=============================================================================
2 handler.c
3===============================================================================
4 This file contains built-in HTTP request handlers.
5
6 Copyright information is at end of file
7=============================================================================*/
8
9#define _XOPEN_SOURCE700 600 /* Make sure strdup() is in <string.h> */
10
11#include <assert.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <time.h>
16#include <errno(*__errno_location ()).h>
17#ifdef WIN32
18 #include <io.h>
19#else
20 #include <unistd.h>
21#endif
22#include <fcntl.h>
23
24#include "xmlrpc_config.h"
25#include "bool.h"
26#include "int.h"
27#include "girmath.h"
28#include "mallocvar.h"
29#include "xmlrpc-c/string_int.h"
30#include "xmlrpc-c/time_int.h"
31
32#include "xmlrpc-c/abyss.h"
33#include "trace.h"
34#include "session.h"
35#include "file.h"
36#include "conn.h"
37#include "http.h"
38#include "date.h"
39#include "abyss_info.h"
40
41#include "handler.h"
42
43
44
45struct BIHandler {
46 const char * filesPath;
47 TList defaultFileNames;
48 MIMEType * mimeTypeP;
49 /* NULL means to use the global MIMEType object */
50};
51
52
53
54BIHandler *
55HandlerCreate(void) {
56
57 struct BIHandler * handlerP;
58
59 MALLOCVAR(handlerP)handlerP = malloc(sizeof(*handlerP));
60
61 if (handlerP) {
62 handlerP->filesPath = strdup(DEFAULT_DOCS)(__extension__ (__builtin_constant_p ("/usr/local/abyss""/htdocs"
) && ((size_t)(const void *)(("/usr/local/abyss""/htdocs"
) + 1) - (size_t)(const void *)("/usr/local/abyss""/htdocs") ==
1) ? (((const char *) ("/usr/local/abyss""/htdocs"))[0] == '\0'
? (char *) calloc ((size_t) 1, (size_t) 1) : ({ size_t __len
= strlen ("/usr/local/abyss""/htdocs") + 1; char *__retval =
(char *) malloc (__len); if (__retval != ((void*)0)) __retval
= (char *) memcpy (__retval, "/usr/local/abyss""/htdocs", __len
); __retval; })) : __strdup ("/usr/local/abyss""/htdocs")))
;
63 ListInitAutoFree(&handlerP->defaultFileNames);
64 handlerP->mimeTypeP = NULL((void*)0);
65 }
66 return handlerP;
67}
68
69
70
71void
72HandlerDestroy(BIHandler * const handlerP) {
73
74 ListFree(&handlerP->defaultFileNames);
75
76 xmlrpc_strfree(handlerP->filesPath);
77
78 free(handlerP);
79}
80
81
82
83void
84HandlerSetMimeType(BIHandler * const handlerP,
85 MIMEType * const mimeTypeP) {
86
87 handlerP->mimeTypeP = mimeTypeP;
88}
89
90
91
92void
93HandlerSetFilesPath(BIHandler * const handlerP,
94 const char * const filesPath) {
95
96 xmlrpc_strfree(handlerP->filesPath);
97 handlerP->filesPath = strdup(filesPath)(__extension__ (__builtin_constant_p (filesPath) && (
(size_t)(const void *)((filesPath) + 1) - (size_t)(const void
*)(filesPath) == 1) ? (((const char *) (filesPath))[0] == '\0'
? (char *) calloc ((size_t) 1, (size_t) 1) : ({ size_t __len
= strlen (filesPath) + 1; char *__retval = (char *) malloc (
__len); if (__retval != ((void*)0)) __retval = (char *) memcpy
(__retval, filesPath, __len); __retval; })) : __strdup (filesPath
)))
;
98}
99
100
101
102void
103HandlerAddDefaultFN(BIHandler * const handlerP,
104 const char * const fileName) {
105
106 ListAdd(&handlerP->defaultFileNames, strdup(fileName)(__extension__ (__builtin_constant_p (fileName) && ((
size_t)(const void *)((fileName) + 1) - (size_t)(const void *
)(fileName) == 1) ? (((const char *) (fileName))[0] == '\0' ?
(char *) calloc ((size_t) 1, (size_t) 1) : ({ size_t __len =
strlen (fileName) + 1; char *__retval = (char *) malloc (__len
); if (__retval != ((void*)0)) __retval = (char *) memcpy (__retval
, fileName, __len); __retval; })) : __strdup (fileName)))
);
107}
108
109
110
111typedef int (*TQSortProc)(const void *, const void *);
112
113static int
114cmpfilenames(const TFileInfo **f1,const TFileInfo **f2) {
115 if (((*f1)->attrib & A_SUBDIR1) && !((*f2)->attrib & A_SUBDIR1))
116 return (-1);
117 if (!((*f1)->attrib & A_SUBDIR1) && ((*f2)->attrib & A_SUBDIR1))
118 return 1;
119
120 return strcmp((*f1)->name,(*f2)->name)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
((*f1)->name) && __builtin_constant_p ((*f2)->
name) && (__s1_len = __builtin_strlen ((*f1)->name
), __s2_len = __builtin_strlen ((*f2)->name), (!((size_t)(
const void *)(((*f1)->name) + 1) - (size_t)(const void *)(
(*f1)->name) == 1) || __s1_len >= 4) && (!((size_t
)(const void *)(((*f2)->name) + 1) - (size_t)(const void *
)((*f2)->name) == 1) || __s2_len >= 4)) ? __builtin_strcmp
((*f1)->name, (*f2)->name) : (__builtin_constant_p ((*
f1)->name) && ((size_t)(const void *)(((*f1)->name
) + 1) - (size_t)(const void *)((*f1)->name) == 1) &&
(__s1_len = __builtin_strlen ((*f1)->name), __s1_len <
4) ? (__builtin_constant_p ((*f2)->name) && ((size_t
)(const void *)(((*f2)->name) + 1) - (size_t)(const void *
)((*f2)->name) == 1) ? __builtin_strcmp ((*f1)->name, (
*f2)->name) : (__extension__ ({ const unsigned char *__s2 =
(const unsigned char *) (const char *) ((*f2)->name); int
__result = (((const unsigned char *) (const char *) ((*f1)->
name))[0] - __s2[0]); if (__s1_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
(*f1)->name))[1] - __s2[1]); if (__s1_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) ((*f1)->name))[2] - __s2[2]); if (__s1_len > 2
&& __result == 0) __result = (((const unsigned char *
) (const char *) ((*f1)->name))[3] - __s2[3]); } } __result
; }))) : (__builtin_constant_p ((*f2)->name) && ((
size_t)(const void *)(((*f2)->name) + 1) - (size_t)(const void
*)((*f2)->name) == 1) && (__s2_len = __builtin_strlen
((*f2)->name), __s2_len < 4) ? (__builtin_constant_p (
(*f1)->name) && ((size_t)(const void *)(((*f1)->
name) + 1) - (size_t)(const void *)((*f1)->name) == 1) ? __builtin_strcmp
((*f1)->name, (*f2)->name) : (- (__extension__ ({ const
unsigned char *__s2 = (const unsigned char *) (const char *)
((*f1)->name); int __result = (((const unsigned char *) (
const char *) ((*f2)->name))[0] - __s2[0]); if (__s2_len >
0 && __result == 0) { __result = (((const unsigned char
*) (const char *) ((*f2)->name))[1] - __s2[1]); if (__s2_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) ((*f2)->name))[2] - __s2[2]); if (
__s2_len > 2 && __result == 0) __result = (((const
unsigned char *) (const char *) ((*f2)->name))[3] - __s2[
3]); } } __result; })))) : __builtin_strcmp ((*f1)->name, (
*f2)->name)))); })
;
121}
122
123
124
125static int
126cmpfiledates(const TFileInfo ** const f1PP,
127 const TFileInfo ** const f2PP) {
128
129 const TFileInfo * const f1P = *f1PP;
130 const TFileInfo * const f2P = *f2PP;
131
132 int retval;
133
134 if ((f1P->attrib & A_SUBDIR1) && !(f2P->attrib & A_SUBDIR1))
135 retval = -1;
136 else if (!(f1P->attrib & A_SUBDIR1) && (f2P->attrib & A_SUBDIR1))
137 retval = 1;
138 else {
139 assert((int)(f1P->time_write - f2P->time_write) ==(((int)(f1P->time_write - f2P->time_write) == (f1P->
time_write - f2P->time_write)) ? (void) (0) : __assert_fail
("(int)(f1P->time_write - f2P->time_write) == (f1P->time_write - f2P->time_write)"
, "../../../../libs/xmlrpc-c/lib/abyss/src/handler.c", 140, __PRETTY_FUNCTION__
))
140 (f1P->time_write - f2P->time_write))(((int)(f1P->time_write - f2P->time_write) == (f1P->
time_write - f2P->time_write)) ? (void) (0) : __assert_fail
("(int)(f1P->time_write - f2P->time_write) == (f1P->time_write - f2P->time_write)"
, "../../../../libs/xmlrpc-c/lib/abyss/src/handler.c", 140, __PRETTY_FUNCTION__
))
;
141 retval = (int)(f1P->time_write - f2P->time_write);
142 }
143 return retval;
144}
145
146
147
148static void
149determineSortType(const char * const query,
150 bool * const ascendingP,
151 uint16_t * const sortP,
152 bool * const textP,
153 const char ** const errorP) {
154
155 *ascendingP = TRUE1;
156 *sortP = 1;
157 *textP = FALSE0;
158 *errorP = NULL((void*)0);
159
160 if (query) {
161 if (xmlrpc_streq(query, "plain"))
162 *textP = TRUE1;
163 else if (xmlrpc_streq(query, "name-up")) {
164 *sortP = 1;
165 *ascendingP = TRUE1;
166 } else if (xmlrpc_streq(query, "name-down")) {
167 *sortP = 1;
168 *ascendingP = FALSE0;
169 } else if (xmlrpc_streq(query, "date-up")) {
170 *sortP = 2;
171 *ascendingP = TRUE1;
172 } else if (xmlrpc_streq(query, "date-down")) {
173 *sortP = 2;
174 *ascendingP = FALSE0;
175 } else {
176 xmlrpc_asprintf(errorP, "invalid query value '%s'", query);
177 }
178 }
179}
180
181
182
183static void
184generateListing(TList * const listP,
185 const char * const dirName,
186 const char * const uri,
187 TPool * const poolP,
188 const char ** const errorP,
189 uint16_t * const responseStatusP) {
190
191 TFileInfo fileinfo;
192 TFileFind * findhandleP;
193
194 *errorP = NULL((void*)0);
195
196 if (!FileFindFirst(&findhandleP, dirName, &fileinfo)) {
197 *responseStatusP = ResponseStatusFromErrno(errno(*__errno_location ()));
198 xmlrpc_asprintf(errorP, "Can't read first entry in directory");
199 } else {
200 ListInit(listP);
201
202 do {
203 TFileInfo * fi;
204 /* Files whose names start with a dot are ignored */
205 /* This includes implicitly the ./ and ../ */
206 if (*fileinfo.name == '.') {
207 if (xmlrpc_streq(fileinfo.name, "..")) {
208 if (xmlrpc_streq(uri, "/"))
209 continue;
210 } else
211 continue;
212 }
213 fi = (TFileInfo *)PoolAlloc(poolP, sizeof(fileinfo));
214 if (fi) {
215 bool success;
216 memcpy(fi, &fileinfo, sizeof(fileinfo));
217 success = ListAdd(listP, fi);
218 if (!success)
219 xmlrpc_asprintf(errorP, "ListAdd() failed");
220 } else
221 xmlrpc_asprintf(errorP, "PoolAlloc() failed.");
222 } while (!*errorP && FileFindNext(findhandleP, &fileinfo));
223
224 if (*errorP) {
225 *responseStatusP = 500;
226 ListFree(listP);
227 }
228 FileFindClose(findhandleP);
229 }
230}
231
232
233
234static void
235sendDirectoryDocument(TList * const listP,
236 bool const ascending,
237 uint16_t const sort,
238 bool const text,
239 const char * const uri,
240 MIMEType * const mimeTypeP,
241 TSession * const sessionP) {
242
243 char z[4096];
244 char *p,z1[26],z2[20],z3[9],u;
245 const char * z4;
246 int16_t i;
247 uint32_t k;
248
249 if (text) {
250 sprintf(z, "Index of %s" CRLF"\r\n", uri);
251 i = strlen(z)-2;
252 p = z + i + 2;
253
254 while (i > 0) {
255 *(p++) = '-';
256 --i;
257 }
258
259 *p = '\0';
260 strcat(z, CRLF"\r\n" CRLF"\r\n"
261 "Name Size "
262 "Date-Time Type" CRLF"\r\n"
263 "------------------------------------"
264 "--------------------------------------------"CRLF"\r\n");
265 } else {
266 sprintf(z, "<HTML><HEAD><TITLE>Index of %s</TITLE></HEAD><BODY>"
267 "<H1>Index of %s</H1><PRE>",
268 uri, uri);
269 strcat(z, "Name Size "
270 "Date-Time Type<HR WIDTH=100%>"CRLF"\r\n");
271 }
272
273 HTTPWriteBodyChunk(sessionP, z, strlen(z));
274
275 /* Sort the files */
276 qsort(listP->item, listP->size, sizeof(void *),
277 (TQSortProc)(sort == 1 ? cmpfilenames : cmpfiledates));
278
279 /* Write the listing */
280 if (ascending)
281 i = 0;
282 else
283 i = listP->size - 1;
284
285 while ((i < listP->size) && (i >= 0)) {
286 TFileInfo * fi;
287 struct tm ftm;
288
289 fi = listP->item[i];
290
291 if (ascending)
292 ++i;
293 else
294 --i;
295
296 strcpy(z, fi->name);
297
298 k = strlen(z);
299
300 if (fi->attrib & A_SUBDIR1) {
301 z[k++] = '/';
302 z[k] = '\0';
303 }
304
305 if (k > 24) {
306 z[10] = '\0';
307 strcpy(z1, z);
308 strcat(z1, "...");
309 strcat(z1, z + k - 11);
310 k = 24;
Value stored to 'k' is never read
311 p = z1 + 24;
312 } else {
313 strcpy(z1, z);
314
315 ++k;
316 p = z1 + k;
317 while (k < 25)
318 z1[k++] = ' ';
319
320 z1[25] = '\0';
321 }
322
323 xmlrpc_gmtime(fi->time_write, &ftm);
324 sprintf(z2, "%02u/%02u/%04u %02u:%02u:%02u",ftm.tm_mday,ftm.tm_mon+1,
325 ftm.tm_year+1900,ftm.tm_hour,ftm.tm_min,ftm.tm_sec);
326
327 if (fi->attrib & A_SUBDIR1) {
328 strcpy(z3, " -- ");
329 z4 = "Directory";
330 } else {
331 if (fi->size < 9999)
332 u = 'b';
333 else {
334 fi->size /= 1024;
335 if (fi->size < 9999)
336 u = 'K';
337 else {
338 fi->size /= 1024;
339 if (fi->size < 9999)
340 u = 'M';
341 else
342 u = 'G';
343 }
344 }
345
346 sprintf(z3, "%5" PRIu64"l" "u" " %c", fi->size, u);
347
348 if (xmlrpc_streq(fi->name, ".."))
349 z4 = "";
350 else
351 z4 = MIMETypeFromFileName2(mimeTypeP, fi->name);
352
353 if (!z4)
354 z4 = "Unknown";
355 }
356
357 if (text)
358 sprintf(z, "%s%s %s %s %s"CRLF"\r\n", z1, p, z3, z2, z4);
359 else
360 sprintf(z, "<A HREF=\"%s%s\">%s</A>%s %s %s %s"CRLF"\r\n",
361 fi->name, fi->attrib & A_SUBDIR1 ? "/" : "",
362 z1, p, z3, z2, z4);
363
364 HTTPWriteBodyChunk(sessionP, z, strlen(z));
365 }
366
367 /* Write the tail of the file */
368 if (text)
369 strcpy(z, SERVER_PLAIN_INFO"\r\n" "----------------------------------------" "----------------------------------------"
"\r\n" "ABYSS Web Server for XML-RPC For C/C++ " "version " "1.26.0"
"\r\n" "See xmlrpc-c.sourceforge.net"
);
370 else
371 strcpy(z, "</PRE>" SERVER_HTML_INFO"<p><HR><b><i><a href=\"http:\057\057xmlrpc-c.sourceforge.net\">"
"ABYSS Web Server for XML-RPC For C/C++</a></i></b> "
"version " "1.26.0" "<br>" "</p>"
"</BODY></HTML>" CRLF"\r\n" CRLF"\r\n");
372
373 HTTPWriteBodyChunk(sessionP, z, strlen(z));
374}
375
376
377
378static bool
379notRecentlyModified(TSession * const sessionP,
380 time_t const fileModTime) {
381
382 bool retval;
383 const char * imsHdr;
384
385 imsHdr = RequestHeaderValue(sessionP, "if-modified-since");
386 if (imsHdr) {
387 bool valid;
388 time_t datetime;
389 DateDecode(imsHdr, &valid, &datetime);
390 if (valid) {
391 if (MIN(fileModTime, sessionP->date)((fileModTime) < (sessionP->date) ? (fileModTime) : (sessionP
->date))
<= datetime)
392 retval = TRUE1;
393 else
394 retval = FALSE0;
395 } else
396 retval = FALSE0;
397 } else
398 retval = FALSE0;
399
400 return retval;
401}
402
403
404
405static void
406addLastModifiedHeader(TSession * const sessionP,
407 time_t const fileModTime) {
408
409 const char * lastModifiedValue;
410
411 DateToString(MIN(fileModTime, sessionP->date)((fileModTime) < (sessionP->date) ? (fileModTime) : (sessionP
->date))
, &lastModifiedValue);
412
413 if (lastModifiedValue) {
414 ResponseAddField(sessionP, "Last-Modified", lastModifiedValue);
415 xmlrpc_strfree(lastModifiedValue);
416 }
417}
418
419
420
421static void
422handleDirectory(TSession * const sessionP,
423 const char * const dirName,
424 time_t const fileModTime,
425 MIMEType * const mimeTypeP) {
426
427 bool text;
428 bool ascending;
429 uint16_t sort; /* 1=by name, 2=by date */
430 const char * error;
431
432 determineSortType(sessionP->requestInfo.query,
433 &ascending, &sort, &text, &error);
434
435 if (error) {
436 ResponseStatus(sessionP, 400);
437 xmlrpc_strfree(error);
438 } else if (notRecentlyModified(sessionP, fileModTime)) {
439 ResponseStatus(sessionP, 304);
440 ResponseWriteStart(sessionP);
441 } else {
442 TPool pool;
443 bool succeeded;
444 succeeded = PoolCreate(&pool, 1024);
445 if (!succeeded)
446 ResponseStatus(sessionP, 500);
447 else {
448 TList list;
449 uint16_t responseStatus;
450 const char * error;
451 generateListing(&list, dirName, sessionP->requestInfo.uri,
452 &pool, &error, &responseStatus);
453 if (error) {
454 ResponseStatus(sessionP, responseStatus);
455 xmlrpc_strfree(error);
456 } else {
457 ResponseStatus(sessionP, 200);
458 ResponseContentType(sessionP,
459 text ? "text/plain" : "text/html");
460
461 addLastModifiedHeader(sessionP, fileModTime);
462
463 ResponseChunked(sessionP);
464 if (ResponseWriteStart(sessionP)) {
465
466 if (sessionP->requestInfo.method!=m_head)
467 sendDirectoryDocument(&list, ascending, sort, text,
468 sessionP->requestInfo.uri, mimeTypeP,
469 sessionP);
470
471 HTTPWriteEndChunk(sessionP);
472 }
473 ListFree(&list);
474 }
475 PoolFree(&pool);
476 }
477 }
478}
479
480
481
482static void
483composeEntityHeader(const char ** const entityHeaderP,
484 const char * const mediatype,
485 uint64_t const start,
486 uint64_t const end,
487 uint64_t const filesize) {
488
489 xmlrpc_asprintf(entityHeaderP, "Content-type: %s" CRLF"\r\n"
490 "Content-range: "
491 "bytes %" PRIu64"l" "u" "-%" PRIu64"l" "u" "/%" PRIu64"l" "u" CRLF"\r\n"
492 "Content-length: %" PRIu64"l" "u" CRLF"\r\n" CRLF"\r\n",
493 mediatype, start, end, filesize, end-start+1);
494}
495
496
497
498#define BOUNDARY"##123456789###BOUNDARY" "##123456789###BOUNDARY"
499
500static void
501sendBody(TSession * const sessionP,
502 const TFile * const fileP,
503 uint64_t const filesize,
504 const char * const mediatype,
505 uint64_t const start0,
506 uint64_t const end0) {
507/*----------------------------------------------------------------------------
508 'start0' and 'end0' are meaningful only if the session has ranges.
509-----------------------------------------------------------------------------*/
510 char buffer[4096*8];
511
512 if (sessionP->ranges.size == 0)
513 ConnWriteFromFile(sessionP->connP, fileP, 0, filesize - 1,
514 buffer, sizeof(buffer), 0);
515 else if (sessionP->ranges.size == 1)
516 ConnWriteFromFile(sessionP->connP, fileP, start0, end0,
517 buffer, sizeof(buffer), 0);
518 else {
519 uint64_t i;
520 for (i = 0; i <= sessionP->ranges.size; ++i) {
521 ConnWrite(sessionP->connP, "--", 2);
522 ConnWrite(sessionP->connP, BOUNDARY"##123456789###BOUNDARY", strlen(BOUNDARY"##123456789###BOUNDARY"));
523 ConnWrite(sessionP->connP, CRLF"\r\n", 2);
524
525 if (i < sessionP->ranges.size) {
526 uint64_t start;
527 uint64_t end;
528 bool decoded;
529
530 decoded = RangeDecode((char *)(sessionP->ranges.item[i]),
531 filesize,
532 &start, &end);
533 if (decoded) {
534 /* Entity header, not response header */
535 const char * entityHeader;
536
537 composeEntityHeader(&entityHeader, mediatype,
538 start, end, filesize);
539
540 ConnWrite(sessionP->connP,
541 entityHeader, strlen(entityHeader));
542
543 xmlrpc_strfree(entityHeader);
544
545 ConnWriteFromFile(sessionP->connP, fileP, start, end,
546 buffer, sizeof(buffer), 0);
547 }
548 }
549 }
550 }
551}
552
553
554
555static void
556sendFileAsResponse(TSession * const sessionP,
557 TFile * const fileP,
558 const char * const fileName,
559 time_t const fileModTime,
560 MIMEType * const mimeTypeP) {
561
562 uint64_t const filesize = FileSize(fileP);
563 const char * const mediatype = MIMETypeGuessFromFile2(mimeTypeP, fileName);
564
565 uint64_t start = 0; /* Defined only if session has one range */
566 uint64_t end = 0; /* Defined only if session has one range */
567
568 switch (sessionP->ranges.size) {
569 case 0:
570 ResponseStatus(sessionP, 200);
571 break;
572
573 case 1: {
574 bool decoded;
575 decoded = RangeDecode((char *)(sessionP->ranges.item[0]), filesize,
576 &start, &end);
577 if (!decoded) {
578 ListFree(&sessionP->ranges);
579 ResponseStatus(sessionP, 200);
580 } else {
581 const char * contentRange;
582 xmlrpc_asprintf(&contentRange,
583 "bytes %" PRIu64"l" "u" "-%" PRIu64"l" "u" "/%" PRIu64"l" "u",
584 start, end, filesize);
585 ResponseAddField(sessionP, "Content-range", contentRange);
586 xmlrpc_strfree(contentRange);
587
588 ResponseContentLength(sessionP, end - start + 1);
589 ResponseStatus(sessionP, 206);
590 }
591 } break;
592
593 default:
594 ResponseContentType(sessionP,
595 "multipart/ranges; boundary=" BOUNDARY"##123456789###BOUNDARY");
596 ResponseStatus(sessionP, 206);
597 break;
598 }
599
600 if (sessionP->ranges.size == 0) {
601 ResponseContentLength(sessionP, filesize);
602 ResponseContentType(sessionP, mediatype);
603 }
604
605 addLastModifiedHeader(sessionP, fileModTime);
606
607 if (ResponseWriteStart(sessionP))
608 if (sessionP->requestInfo.method != m_head)
609 sendBody(sessionP, fileP, filesize, mediatype, start, end);
610}
611
612
613
614static void
615handleFile(TSession * const sessionP,
616 const char * const fileName,
617 time_t const fileModTime,
618 MIMEType * const mimeTypeP) {
619/*----------------------------------------------------------------------------
620 This is an HTTP request handler for a GET. It does the classic
621 web server thing: send the file named in the URL to the client.
622-----------------------------------------------------------------------------*/
623 TFile * fileP;
624 bool success;
625
626 success = FileOpen(&fileP, fileName, O_BINARY0 | O_RDONLY00);
627 if (!success)
628 ResponseStatusErrno(sessionP);
629 else {
630 if (notRecentlyModified(sessionP, fileModTime)) {
631 ResponseStatus(sessionP, 304);
632 ResponseWriteStart(sessionP);
633 } else
634 sendFileAsResponse(sessionP, fileP,
635 fileName, fileModTime, mimeTypeP);
636
637 FileClose(fileP);
638 }
639}
640
641
642
643static void
644convertToNativeFileName(char * const fileName ATTR_UNUSED__attribute__((__unused__))) {
645
646#ifdef WIN32
647 char * p;
648 p = &fileName[0];
649 while (*p) {
650 if ((*p) == '/')
651 *p= '\\';
652
653 ++p;
654 }
655#endif /* WIN32 */
656}
657
658
659
660abyss_bool
661HandlerDefaultBuiltin(TSession * const sessionP) {
662
663 BIHandler * const handlerP = SessionGetDefaultHandlerCtx(sessionP);
664
665 char * p;
666 char z[4096];
667 TFileStat fs;
668 bool endingslash;
669
670 endingslash = FALSE0; /* initial value */
671
672 if (!RequestValidURIPath(sessionP)) {
673 ResponseStatus(sessionP, 400);
674 return TRUE1;
675 }
676
677 /* Must check for * (asterisk uri) in the future */
678 if (sessionP->requestInfo.method == m_options) {
679 ResponseAddField(sessionP, "Allow", "GET, HEAD");
680 ResponseContentLength(sessionP, 0);
681 ResponseStatus(sessionP, 200);
682 return TRUE1;
683 }
684
685 if ((sessionP->requestInfo.method != m_get) &&
686 (sessionP->requestInfo.method != m_head)) {
687 ResponseAddField(sessionP, "Allow", "GET, HEAD");
688 ResponseStatus(sessionP, 405);
689 return TRUE1;
690 }
691
692 strcpy(z, handlerP->filesPath);
693 strcat(z, sessionP->requestInfo.uri);
694
695 p = z + strlen(z) - 1;
696 if (*p == '/') {
697 endingslash = TRUE1;
698 *p = '\0';
699 }
700
701 convertToNativeFileName(z);
702
703 if (!FileStat(z, &fs)) {
704 ResponseStatusErrno(sessionP);
705 return TRUE1;
706 }
707
708 if (fs.st_mode & S_IFDIR0040000) {
709 /* Redirect to the same directory but with the ending slash
710 ** to avoid problems with some browsers (IE for examples) when
711 ** they generate relative urls */
712 if (!endingslash) {
713 strcpy(z, sessionP->requestInfo.uri);
714 p = z+strlen(z);
715 *p = '/';
716 *(p+1) = '\0';
717 ResponseAddField(sessionP, "Location", z);
718 ResponseStatus(sessionP, 302);
719 ResponseWriteStart(sessionP);
720 return TRUE1;
721 }
722
723 *p = DIRECTORY_SEPARATOR"/"[0];
724 ++p;
725 {
726 unsigned int i;
727 i = handlerP->defaultFileNames.size;
728 while (i-- > 0) {
729 *p = '\0';
730 strcat(z, (handlerP->defaultFileNames.item[i]));
731 if (FileStat(z, &fs)) {
732 if (!(fs.st_mode & S_IFDIR0040000))
733 handleFile(sessionP, z, fs.st_mtimest_mtim.tv_sec,
734 handlerP->mimeTypeP);
735 }
736 }
737 }
738
739 *(p-1) = '\0';
740
741 if (!FileStat(z, &fs)) {
742 ResponseStatusErrno(sessionP);
743 return TRUE1;
744 }
745 handleDirectory(sessionP, z, fs.st_mtimest_mtim.tv_sec, handlerP->mimeTypeP);
746 } else
747 handleFile(sessionP, z, fs.st_mtimest_mtim.tv_sec, handlerP->mimeTypeP);
748
749 return TRUE1;
750}
751
752
753
754size_t const HandlerDefaultBuiltinStack = 1024;
755
756
757/******************************************************************************
758**
759** server.c
760**
761** This file is part of the ABYSS Web server project.
762**
763** Copyright (C) 2000 by Moez Mahfoudh <mmoez@bigfoot.com>.
764** All rights reserved.
765**
766** Redistribution and use in source and binary forms, with or without
767** modification, are permitted provided that the following conditions
768** are met:
769** 1. Redistributions of source code must retain the above copyright
770** notice, this list of conditions and the following disclaimer.
771** 2. Redistributions in binary form must reproduce the above copyright
772** notice, this list of conditions and the following disclaimer in the
773** documentation and/or other materials provided with the distribution.
774** 3. The name of the author may not be used to endorse or promote products
775** derived from this software without specific prior written permission.
776**
777** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
778** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
779** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
780** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
781** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
782** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
783** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
784** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
785** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
786** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
787** SUCH DAMAGE.
788**
789******************************************************************************/