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 |
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 | |
45 | struct BIHandler { |
46 | const char * filesPath; |
47 | TList defaultFileNames; |
48 | MIMEType * mimeTypeP; |
49 | /* NULL means to use the global MIMEType object */ |
50 | }; |
51 | |
52 | |
53 | |
54 | BIHandler * |
55 | HandlerCreate(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 | |
71 | void |
72 | HandlerDestroy(BIHandler * const handlerP) { |
73 | |
74 | ListFree(&handlerP->defaultFileNames); |
75 | |
76 | xmlrpc_strfree(handlerP->filesPath); |
77 | |
78 | free(handlerP); |
79 | } |
80 | |
81 | |
82 | |
83 | void |
84 | HandlerSetMimeType(BIHandler * const handlerP, |
85 | MIMEType * const mimeTypeP) { |
86 | |
87 | handlerP->mimeTypeP = mimeTypeP; |
88 | } |
89 | |
90 | |
91 | |
92 | void |
93 | HandlerSetFilesPath(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 | |
102 | void |
103 | HandlerAddDefaultFN(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 | |
111 | typedef int (*TQSortProc)(const void *, const void *); |
112 | |
113 | static int |
114 | cmpfilenames(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 | |
125 | static int |
126 | cmpfiledates(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 | |
148 | static void |
149 | determineSortType(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 | |
183 | static void |
184 | generateListing(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 | |
234 | static void |
235 | sendDirectoryDocument(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 | |
378 | static bool |
379 | notRecentlyModified(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 | |
405 | static void |
406 | addLastModifiedHeader(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 | |
421 | static void |
422 | handleDirectory(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 | |
482 | static void |
483 | composeEntityHeader(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 | |
500 | static void |
501 | sendBody(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 | |
555 | static void |
556 | sendFileAsResponse(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 | |
614 | static void |
615 | handleFile(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 | |
643 | static void |
644 | convertToNativeFileName(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 | |
660 | abyss_bool |
661 | HandlerDefaultBuiltin(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 | |
754 | size_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 | ******************************************************************************/ |