1 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,1797 +0,0 @@ |
1 |
-/* Copyright information is at end of file */ |
|
2 |
-#include <assert.h> |
|
3 |
-#include <stdio.h> |
|
4 |
-#include <stdlib.h> |
|
5 |
-#include <string.h> |
|
6 |
-#include <time.h> |
|
7 |
-#include <errno.h> |
|
8 |
-#ifdef WIN32 |
|
9 |
- #include <io.h> |
|
10 |
-#else |
|
11 |
- #include <unistd.h> |
|
12 |
- #include <grp.h> |
|
13 |
-#endif |
|
14 |
-#include <fcntl.h> |
|
15 |
- |
|
16 |
-#include <xmlrpc-c/config.h> |
|
17 |
-#include "abyss_mallocvar.h" |
|
18 |
-#include "abyss_xmlrpc_int.h" |
|
19 |
- |
|
20 |
-#include <xmlrpc-c/abyss.h> |
|
21 |
-#include "abyss_trace.h" |
|
22 |
-#include "abyss_session.h" |
|
23 |
-#include "abyss_conn.h" |
|
24 |
-#include "abyss_socket.h" |
|
25 |
-#ifdef WIN32 |
|
26 |
- #include "socket_win.h" |
|
27 |
-#else |
|
28 |
- #include "abyss_socket_unix.h" |
|
29 |
-#endif |
|
30 |
-#include "abyss_http.h" |
|
31 |
-#include "abyss_date.h" |
|
32 |
-#include "abyss_info.h" |
|
33 |
- |
|
34 |
-#include "abyss_server.h" |
|
35 |
- |
|
36 |
- |
|
37 |
-void |
|
38 |
-ServerTerminate(TServer * const serverP) { |
|
39 |
- |
|
40 |
- struct _TServer * const srvP = serverP->srvP; |
|
41 |
- |
|
42 |
- srvP->terminationRequested = true; |
|
43 |
-} |
|
44 |
- |
|
45 |
- |
|
46 |
- |
|
47 |
-void |
|
48 |
-ServerResetTerminate(TServer * const serverP) { |
|
49 |
- |
|
50 |
- struct _TServer * const srvP = serverP->srvP; |
|
51 |
- |
|
52 |
- srvP->terminationRequested = false; |
|
53 |
-} |
|
54 |
- |
|
55 |
- |
|
56 |
- |
|
57 |
-typedef int (*TQSortProc)(const void *, const void *); |
|
58 |
- |
|
59 |
-static int |
|
60 |
-cmpfilenames(const TFileInfo **f1,const TFileInfo **f2) { |
|
61 |
- if (((*f1)->attrib & A_SUBDIR) && !((*f2)->attrib & A_SUBDIR)) |
|
62 |
- return (-1); |
|
63 |
- if (!((*f1)->attrib & A_SUBDIR) && ((*f2)->attrib & A_SUBDIR)) |
|
64 |
- return 1; |
|
65 |
- |
|
66 |
- return strcmp((*f1)->name,(*f2)->name); |
|
67 |
-} |
|
68 |
- |
|
69 |
-static int |
|
70 |
-cmpfiledates(const TFileInfo **f1,const TFileInfo **f2) { |
|
71 |
- if (((*f1)->attrib & A_SUBDIR) && !((*f2)->attrib & A_SUBDIR)) |
|
72 |
- return (-1); |
|
73 |
- if (!((*f1)->attrib & A_SUBDIR) && ((*f2)->attrib & A_SUBDIR)) |
|
74 |
- return 1; |
|
75 |
- |
|
76 |
- return ((*f1)->time_write-(*f2)->time_write); |
|
77 |
-} |
|
78 |
- |
|
79 |
- |
|
80 |
- |
|
81 |
-static void |
|
82 |
-determineSortType(const char * const query, |
|
83 |
- abyss_bool * const ascendingP, |
|
84 |
- uint16_t * const sortP, |
|
85 |
- abyss_bool * const textP, |
|
86 |
- const char ** const errorP) { |
|
87 |
- |
|
88 |
- *ascendingP = TRUE; |
|
89 |
- *sortP = 1; |
|
90 |
- *textP = FALSE; |
|
91 |
- *errorP = NULL; |
|
92 |
- |
|
93 |
- if (query) { |
|
94 |
- if (xmlrpc_streq(query, "plain")) |
|
95 |
- *textP = TRUE; |
|
96 |
- else if (xmlrpc_streq(query, "name-up")) { |
|
97 |
- *sortP = 1; |
|
98 |
- *ascendingP = TRUE; |
|
99 |
- } else if (xmlrpc_streq(query, "name-down")) { |
|
100 |
- *sortP = 1; |
|
101 |
- *ascendingP = FALSE; |
|
102 |
- } else if (xmlrpc_streq(query, "date-up")) { |
|
103 |
- *sortP = 2; |
|
104 |
- *ascendingP = TRUE; |
|
105 |
- } else if (xmlrpc_streq(query, "date-down")) { |
|
106 |
- *sortP = 2; |
|
107 |
- *ascendingP = FALSE; |
|
108 |
- } else { |
|
109 |
- xmlrpc_asprintf(errorP, "invalid query value '%s'", query); |
|
110 |
- } |
|
111 |
- } |
|
112 |
-} |
|
113 |
- |
|
114 |
- |
|
115 |
- |
|
116 |
-static void |
|
117 |
-generateListing(TList * const listP, |
|
118 |
- char * const z, |
|
119 |
- const char * const uri, |
|
120 |
- TPool * const poolP, |
|
121 |
- const char ** const errorP, |
|
122 |
- uint16_t * const responseStatusP) { |
|
123 |
- |
|
124 |
- TFileInfo fileinfo; |
|
125 |
- TFileFind findhandle; |
|
126 |
- |
|
127 |
- *errorP = NULL; |
|
128 |
- |
|
129 |
- if (!FileFindFirst(&findhandle, z, &fileinfo)) { |
|
130 |
- *responseStatusP = ResponseStatusFromErrno(errno); |
|
131 |
- xmlrpc_asprintf(errorP, "Can't read first entry in directory"); |
|
132 |
- } else { |
|
133 |
- ListInit(listP); |
|
134 |
- |
|
135 |
- do { |
|
136 |
- TFileInfo * fi; |
|
137 |
- /* Files whose names start with a dot are ignored */ |
|
138 |
- /* This includes implicitly the ./ and ../ */ |
|
139 |
- if (*fileinfo.name == '.') { |
|
140 |
- if (xmlrpc_streq(fileinfo.name, "..")) { |
|
141 |
- if (xmlrpc_streq(uri, "/")) |
|
142 |
- continue; |
|
143 |
- } else |
|
144 |
- continue; |
|
145 |
- } |
|
146 |
- fi = (TFileInfo *)PoolAlloc(poolP, sizeof(fileinfo)); |
|
147 |
- if (fi) { |
|
148 |
- abyss_bool success; |
|
149 |
- memcpy(fi, &fileinfo, sizeof(fileinfo)); |
|
150 |
- success = ListAdd(listP, fi); |
|
151 |
- if (!success) |
|
152 |
- xmlrpc_asprintf(errorP, "ListAdd() failed"); |
|
153 |
- } else |
|
154 |
- xmlrpc_asprintf(errorP, "PoolAlloc() failed."); |
|
155 |
- } while (!*errorP && FileFindNext(&findhandle, &fileinfo)); |
|
156 |
- |
|
157 |
- if (*errorP) { |
|
158 |
- *responseStatusP = 500; |
|
159 |
- ListFree(listP); |
|
160 |
- } |
|
161 |
- FileFindClose(&findhandle); |
|
162 |
- } |
|
163 |
-} |
|
164 |
- |
|
165 |
- |
|
166 |
- |
|
167 |
-static void |
|
168 |
-sendDirectoryDocument(TList * const listP, |
|
169 |
- abyss_bool const ascending, |
|
170 |
- uint16_t const sort, |
|
171 |
- abyss_bool const text, |
|
172 |
- const char * const uri, |
|
173 |
- MIMEType * const mimeTypeP, |
|
174 |
- TSession * const sessionP, |
|
175 |
- char * const z) { |
|
176 |
- |
|
177 |
- char *p,z1[26],z2[20],z3[9],u; |
|
178 |
- const char * z4; |
|
179 |
- int16_t i; |
|
180 |
- uint32_t k; |
|
181 |
- |
|
182 |
- if (text) { |
|
183 |
- sprintf(z, "Index of %s" CRLF, uri); |
|
184 |
- i = strlen(z)-2; |
|
185 |
- p = z + i + 2; |
|
186 |
- |
|
187 |
- while (i > 0) { |
|
188 |
- *(p++) = '-'; |
|
189 |
- --i; |
|
190 |
- } |
|
191 |
- |
|
192 |
- *p = '\0'; |
|
193 |
- strcat(z, CRLF CRLF |
|
194 |
- "Name Size " |
|
195 |
- "Date-Time Type" CRLF |
|
196 |
- "------------------------------------" |
|
197 |
- "--------------------------------------------"CRLF); |
|
198 |
- } else { |
|
199 |
- sprintf(z, "<HTML><HEAD><TITLE>Index of %s</TITLE></HEAD><BODY>" |
|
200 |
- "<H1>Index of %s</H1><PRE>", |
|
201 |
- uri, uri); |
|
202 |
- strcat(z, "Name Size " |
|
203 |
- "Date-Time Type<HR WIDTH=100%>"CRLF); |
|
204 |
- } |
|
205 |
- |
|
206 |
- HTTPWriteBodyChunk(sessionP, z, strlen(z)); |
|
207 |
- |
|
208 |
- /* Sort the files */ |
|
209 |
- qsort(listP->item, listP->size, sizeof(void *), |
|
210 |
- (TQSortProc)(sort == 1 ? cmpfilenames : cmpfiledates)); |
|
211 |
- |
|
212 |
- /* Write the listing */ |
|
213 |
- if (ascending) |
|
214 |
- i = 0; |
|
215 |
- else |
|
216 |
- i = listP->size - 1; |
|
217 |
- |
|
218 |
- while ((i < listP->size) && (i >= 0)) { |
|
219 |
- TFileInfo * fi; |
|
220 |
- struct tm ftm; |
|
221 |
- |
|
222 |
- fi = listP->item[i]; |
|
223 |
- |
|
224 |
- if (ascending) |
|
225 |
- ++i; |
|
226 |
- else |
|
227 |
- --i; |
|
228 |
- |
|
229 |
- strcpy(z, fi->name); |
|
230 |
- |
|
231 |
- k = strlen(z); |
|
232 |
- |
|
233 |
- if (fi->attrib & A_SUBDIR) { |
|
234 |
- z[k++] = '/'; |
|
235 |
- z[k] = '\0'; |
|
236 |
- } |
|
237 |
- |
|
238 |
- if (k > 24) { |
|
239 |
- z[10] = '\0'; |
|
240 |
- strcpy(z1, z); |
|
241 |
- strcat(z1, "..."); |
|
242 |
- strcat(z1, z + k - 11); |
|
243 |
- k = 24; |
|
244 |
- p = z1 + 24; |
|
245 |
- } else { |
|
246 |
- strcpy(z1, z); |
|
247 |
- |
|
248 |
- ++k; |
|
249 |
- p = z1 + k; |
|
250 |
- while (k < 25) |
|
251 |
- z1[k++] = ' '; |
|
252 |
- |
|
253 |
- z1[25] = '\0'; |
|
254 |
- } |
|
255 |
- |
|
256 |
- ftm = *gmtime(&fi->time_write); |
|
257 |
- sprintf(z2, "%02u/%02u/%04u %02u:%02u:%02u",ftm.tm_mday,ftm.tm_mon+1, |
|
258 |
- ftm.tm_year+1900,ftm.tm_hour,ftm.tm_min,ftm.tm_sec); |
|
259 |
- |
|
260 |
- if (fi->attrib & A_SUBDIR) { |
|
261 |
- strcpy(z3, " -- "); |
|
262 |
- z4 = "Directory"; |
|
263 |
- } else { |
|
264 |
- if (fi->size < 9999) |
|
265 |
- u = 'b'; |
|
266 |
- else { |
|
267 |
- fi->size /= 1024; |
|
268 |
- if (fi->size < 9999) |
|
269 |
- u = 'K'; |
|
270 |
- else { |
|
271 |
- fi->size /= 1024; |
|
272 |
- if (fi->size < 9999) |
|
273 |
- u = 'M'; |
|
274 |
- else |
|
275 |
- u = 'G'; |
|
276 |
- } |
|
277 |
- } |
|
278 |
- |
|
279 |
- sprintf(z3, "%5llu %c", (long long unsigned int)fi->size, u); |
|
280 |
- |
|
281 |
- if (xmlrpc_streq(fi->name, "..")) |
|
282 |
- z4 = ""; |
|
283 |
- else |
|
284 |
- z4 = MIMETypeFromFileName2(mimeTypeP, fi->name); |
|
285 |
- |
|
286 |
- if (!z4) |
|
287 |
- z4 = "Unknown"; |
|
288 |
- } |
|
289 |
- |
|
290 |
- if (text) |
|
291 |
- sprintf(z, "%s%s %s %s %s"CRLF, z1, p, z3, z2, z4); |
|
292 |
- else |
|
293 |
- sprintf(z, "<A HREF=\"%s%s\">%s</A>%s %s %s %s"CRLF, |
|
294 |
- fi->name, fi->attrib & A_SUBDIR ? "/" : "", |
|
295 |
- z1, p, z3, z2, z4); |
|
296 |
- |
|
297 |
- HTTPWriteBodyChunk(sessionP, z, strlen(z)); |
|
298 |
- } |
|
299 |
- |
|
300 |
- /* Write the tail of the file */ |
|
301 |
- if (text) |
|
302 |
- strcpy(z, SERVER_PLAIN_INFO); |
|
303 |
- else |
|
304 |
- strcpy(z, "</PRE>" SERVER_HTML_INFO "</BODY></HTML>" CRLF CRLF); |
|
305 |
- |
|
306 |
- HTTPWriteBodyChunk(sessionP, z, strlen(z)); |
|
307 |
-} |
|
308 |
- |
|
309 |
- |
|
310 |
- |
|
311 |
-static void |
|
312 |
-fileDate(TSession * const sessionP, |
|
313 |
- time_t const statFilemodTime, |
|
314 |
- TDate * const fileDateP) { |
|
315 |
- |
|
316 |
- abyss_bool haveDate; |
|
317 |
- TDate filemodDate; |
|
318 |
- |
|
319 |
- haveDate = DateFromLocal(&filemodDate, statFilemodTime); |
|
320 |
- |
|
321 |
- if (haveDate) { |
|
322 |
- if (DateCompare(&sessionP->date, &filemodDate) < 0) |
|
323 |
- *fileDateP = sessionP->date; |
|
324 |
- else |
|
325 |
- *fileDateP = filemodDate; |
|
326 |
- } else |
|
327 |
- *fileDateP = sessionP->date; |
|
328 |
-} |
|
329 |
- |
|
330 |
- |
|
331 |
- |
|
332 |
-static abyss_bool |
|
333 |
-ServerDirectoryHandler(TSession * const r, |
|
334 |
- char * const z, |
|
335 |
- time_t const fileModTime, |
|
336 |
- MIMEType * const mimeTypeP) { |
|
337 |
- |
|
338 |
- TList list; |
|
339 |
- abyss_bool text; |
|
340 |
- abyss_bool ascending; |
|
341 |
- uint16_t sort; /* 1=by name, 2=by date */ |
|
342 |
- TPool pool; |
|
343 |
- TDate date; |
|
344 |
- const char * error; |
|
345 |
- uint16_t responseStatus=0; |
|
346 |
- TDate dirdate; |
|
347 |
- const char * imsHdr; |
|
348 |
- |
|
349 |
- determineSortType(r->request_info.query, &ascending, &sort, &text, &error); |
|
350 |
- |
|
351 |
- if (error) { |
|
352 |
- ResponseStatus(r,400); |
|
353 |
- xmlrpc_strfree(error); |
|
354 |
- return TRUE; |
|
355 |
- } |
|
356 |
- |
|
357 |
- fileDate(r, fileModTime, &dirdate); |
|
358 |
- |
|
359 |
- imsHdr = RequestHeaderValue(r, "If-Modified-Since"); |
|
360 |
- if (imsHdr) { |
|
361 |
- if (DateDecode(imsHdr, &date)) { |
|
362 |
- if (DateCompare(&dirdate, &date) <= 0) { |
|
363 |
- ResponseStatus(r, 304); |
|
364 |
- ResponseWrite(r); |
|
365 |
- return TRUE; |
|
366 |
- } |
|
367 |
- } |
|
368 |
- } |
|
369 |
- |
|
370 |
- if (!PoolCreate(&pool, 1024)) { |
|
371 |
- ResponseStatus(r, 500); |
|
372 |
- return TRUE; |
|
373 |
- } |
|
374 |
- |
|
375 |
- generateListing(&list, z, r->request_info.uri, |
|
376 |
- &pool, &error, &responseStatus); |
|
377 |
- if (error) { |
|
378 |
- ResponseStatus(r, responseStatus); |
|
379 |
- xmlrpc_strfree(error); |
|
380 |
- PoolFree(&pool); |
|
381 |
- return TRUE; |
|
382 |
- } |
|
383 |
- |
|
384 |
- /* Send something to the user to show that we are still alive */ |
|
385 |
- ResponseStatus(r, 200); |
|
386 |
- ResponseContentType(r, (text ? "text/plain" : "text/html")); |
|
387 |
- |
|
388 |
- if (DateToString(&dirdate, z)) |
|
389 |
- ResponseAddField(r, "Last-Modified", z); |
|
390 |
- |
|
391 |
- ResponseChunked(r); |
|
392 |
- ResponseWrite(r); |
|
393 |
- |
|
394 |
- if (r->request_info.method!=m_head) |
|
395 |
- sendDirectoryDocument(&list, ascending, sort, text, |
|
396 |
- r->request_info.uri, mimeTypeP, r, z); |
|
397 |
- |
|
398 |
- HTTPWriteEndChunk(r); |
|
399 |
- |
|
400 |
- /* Free memory and exit */ |
|
401 |
- ListFree(&list); |
|
402 |
- PoolFree(&pool); |
|
403 |
- |
|
404 |
- return TRUE; |
|
405 |
-} |
|
406 |
- |
|
407 |
- |
|
408 |
- |
|
409 |
-#define BOUNDARY "##123456789###BOUNDARY" |
|
410 |
- |
|
411 |
-static void |
|
412 |
-sendBody(TSession * const sessionP, |
|
413 |
- TFile * const fileP, |
|
414 |
- uint64_t const filesize, |
|
415 |
- const char * const mediatype, |
|
416 |
- uint64_t const start0, |
|
417 |
- uint64_t const end0, |
|
418 |
- char * const z) { |
|
419 |
- |
|
420 |
- if (sessionP->ranges.size == 0) |
|
421 |
- ConnWriteFromFile(sessionP->conn, fileP, 0, filesize - 1, z, 4096, 0); |
|
422 |
- else if (sessionP->ranges.size == 1) |
|
423 |
- ConnWriteFromFile(sessionP->conn, fileP, start0, end0, z, 4096, 0); |
|
424 |
- else { |
|
425 |
- uint64_t i; |
|
426 |
- for (i = 0; i <= sessionP->ranges.size; ++i) { |
|
427 |
- ConnWrite(sessionP->conn,"--", 2); |
|
428 |
- ConnWrite(sessionP->conn, BOUNDARY, strlen(BOUNDARY)); |
|
429 |
- ConnWrite(sessionP->conn, CRLF, 2); |
|
430 |
- |
|
431 |
- if (i < sessionP->ranges.size) { |
|
432 |
- uint64_t start; |
|
433 |
- uint64_t end; |
|
434 |
- abyss_bool decoded; |
|
435 |
- |
|
436 |
- decoded = RangeDecode((char *)(sessionP->ranges.item[i]), |
|
437 |
- filesize, |
|
438 |
- &start, &end); |
|
439 |
- if (decoded) { |
|
440 |
- /* Entity header, not response header */ |
|
441 |
- sprintf(z, "Content-type: %s" CRLF |
|
442 |
- "Content-range: bytes %llu-%llu/%llu" CRLF |
|
443 |
- "Content-length: %llu" CRLF |
|
444 |
- CRLF, mediatype, (long long unsigned int)start, |
|
445 |
- (long long unsigned int)end, |
|
446 |
- (long long unsigned int)filesize, |
|
447 |
- (long long unsigned int)(end-start+1)); |
|
448 |
- |
|
449 |
- ConnWrite(sessionP->conn, z, strlen(z)); |
|
450 |
- |
|
451 |
- ConnWriteFromFile(sessionP->conn, fileP, start, end, z, |
|
452 |
- 4096, 0); |
|
453 |
- } |
|
454 |
- } |
|
455 |
- } |
|
456 |
- } |
|
457 |
-} |
|
458 |
- |
|
459 |
- |
|
460 |
- |
|
461 |
-static abyss_bool |
|
462 |
-ServerFileHandler(TSession * const r, |
|
463 |
- char * const z, |
|
464 |
- time_t const fileModTime, |
|
465 |
- MIMEType * const mimeTypeP) { |
|
466 |
- |
|
467 |
- const char * mediatype; |
|
468 |
- TFile file; |
|
469 |
- uint64_t filesize; |
|
470 |
- uint64_t start; |
|
471 |
- uint64_t end; |
|
472 |
- TDate date; |
|
473 |
- char * p; |
|
474 |
- TDate filedate; |
|
475 |
- |
|
476 |
- mediatype = MIMETypeGuessFromFile2(mimeTypeP, z); |
|
477 |
- |
|
478 |
- if (!FileOpen(&file,z,O_BINARY | O_RDONLY)) { |
|
479 |
- ResponseStatusErrno(r); |
|
480 |
- return TRUE; |
|
481 |
- } |
|
482 |
- |
|
483 |
- fileDate(r, fileModTime, &filedate); |
|
484 |
- |
|
485 |
- p = RequestHeaderValue(r, "if-modified-since"); |
|
486 |
- if (p) { |
|
487 |
- if (DateDecode(p,&date)) { |
|
488 |
- if (DateCompare(&filedate, &date) <= 0) { |
|
489 |
- ResponseStatus(r, 304); |
|
490 |
- ResponseWrite(r); |
|
491 |
- return TRUE; |
|
492 |
- } else |
|
493 |
- r->ranges.size = 0; |
|
494 |
- } |
|
495 |
- } |
|
496 |
- filesize = FileSize(&file); |
|
497 |
- |
|
498 |
- switch (r->ranges.size) { |
|
499 |
- case 0: |
|
500 |
- ResponseStatus(r, 200); |
|
501 |
- break; |
|
502 |
- |
|
503 |
- case 1: { |
|
504 |
- abyss_bool decoded; |
|
505 |
- decoded = RangeDecode((char *)(r->ranges.item[0]), filesize, |
|
506 |
- &start, &end); |
|
507 |
- if (!decoded) { |
|
508 |
- ListFree(&(r->ranges)); |
|
509 |
- ResponseStatus(r, 200); |
|
510 |
- break; |
|
511 |
- } |
|
512 |
- |
|
513 |
- sprintf(z, "bytes %llu-%llu/%llu", (long long unsigned int)start, |
|
514 |
- (long long unsigned int)end, (long long unsigned int)filesize); |
|
515 |
- |
|
516 |
- ResponseAddField(r, "Content-range", z); |
|
517 |
- ResponseContentLength(r, end - start + 1); |
|
518 |
- ResponseStatus(r, 206); |
|
519 |
- } break; |
|
520 |
- |
|
521 |
- default: |
|
522 |
- ResponseContentType(r, "multipart/ranges; boundary=" BOUNDARY); |
|
523 |
- ResponseStatus(r, 206); |
|
524 |
- break; |
|
525 |
- } |
|
526 |
- |
|
527 |
- if (r->ranges.size == 0) { |
|
528 |
- ResponseContentLength(r, filesize); |
|
529 |
- ResponseContentType(r, mediatype); |
|
530 |
- } |
|
531 |
- |
|
532 |
- if (DateToString(&filedate, z)) |
|
533 |
- ResponseAddField(r, "Last-Modified", z); |
|
534 |
- |
|
535 |
- ResponseWrite(r); |
|
536 |
- |
|
537 |
- if (r->request_info.method != m_head) |
|
538 |
- sendBody(r, &file, filesize, mediatype, start, end, z); |
|
539 |
- |
|
540 |
- FileClose(&file); |
|
541 |
- |
|
542 |
- return TRUE; |
|
543 |
-} |
|
544 |
- |
|
545 |
- |
|
546 |
- |
|
547 |
-static abyss_bool |
|
548 |
-ServerDefaultHandlerFunc(TSession * const sessionP) { |
|
549 |
- |
|
550 |
- struct _TServer * const srvP = ConnServer(sessionP->conn)->srvP; |
|
551 |
- |
|
552 |
- char *p; |
|
553 |
- char z[4096]; |
|
554 |
- TFileStat fs; |
|
555 |
- unsigned int i; |
|
556 |
- abyss_bool endingslash=FALSE; |
|
557 |
- |
|
558 |
- if (!RequestValidURIPath(sessionP)) { |
|
559 |
- ResponseStatus(sessionP, 400); |
|
560 |
- return TRUE; |
|
561 |
- } |
|
562 |
- |
|
563 |
- /* Must check for * (asterisk uri) in the future */ |
|
564 |
- if (sessionP->request_info.method == m_options) { |
|
565 |
- ResponseAddField(sessionP, "Allow", "GET, HEAD"); |
|
566 |
- ResponseContentLength(sessionP, 0); |
|
567 |
- ResponseStatus(sessionP, 200); |
|
568 |
- return TRUE; |
|
569 |
- } |
|
570 |
- |
|
571 |
- if ((sessionP->request_info.method != m_get) && |
|
572 |
- (sessionP->request_info.method != m_head)) { |
|
573 |
- ResponseAddField(sessionP, "Allow", "GET, HEAD"); |
|
574 |
- ResponseStatus(sessionP, 405); |
|
575 |
- return TRUE; |
|
576 |
- } |
|
577 |
- |
|
578 |
- strcpy(z, srvP->filespath); |
|
579 |
- strcat(z, sessionP->request_info.uri); |
|
580 |
- |
|
581 |
- p = z + strlen(z) - 1; |
|
582 |
- if (*p == '/') { |
|
583 |
- endingslash = TRUE; |
|
584 |
- *p = '\0'; |
|
585 |
- } |
|
586 |
- |
|
587 |
-#ifdef WIN32 |
|
588 |
- p = z; |
|
589 |
- while (*p) { |
|
590 |
- if ((*p) == '/') |
|
591 |
- *p= '\\'; |
|
592 |
- |
|
593 |
- ++p; |
|
594 |
- } |
|
595 |
-#endif /* WIN32 */ |
|
596 |
- |
|
597 |
- if (!FileStat(z, &fs)) { |
|
598 |
- ResponseStatusErrno(sessionP); |
|
599 |
- return TRUE; |
|
600 |
- } |
|
601 |
- |
|
602 |
- if (fs.st_mode & S_IFDIR) { |
|
603 |
- /* Redirect to the same directory but with the ending slash |
|
604 |
- ** to avoid problems with some browsers (IE for examples) when |
|
605 |
- ** they generate relative urls */ |
|
606 |
- if (!endingslash) { |
|
607 |
- strcpy(z, sessionP->request_info.uri); |
|
608 |
- p = z+strlen(z); |
|
609 |
- *p = '/'; |
|
610 |
- *(p+1) = '\0'; |
|
611 |
- ResponseAddField(sessionP, "Location", z); |
|
612 |
- ResponseStatus(sessionP, 302); |
|
613 |
- ResponseWrite(sessionP); |
|
614 |
- return TRUE; |
|
615 |
- } |
|
616 |
- |
|
617 |
- *p = DIRECTORY_SEPARATOR[0]; |
|
618 |
- ++p; |
|
619 |
- |
|
620 |
- i = srvP->defaultfilenames.size; |
|
621 |
- while (i-- > 0) { |
|
622 |
- *p = '\0'; |
|
623 |
- strcat(z, (srvP->defaultfilenames.item[i])); |
|
624 |
- if (FileStat(z, &fs)) { |
|
625 |
- if (!(fs.st_mode & S_IFDIR)) |
|
626 |
- return ServerFileHandler(sessionP, z, fs.st_mtime, |
|
627 |
- srvP->mimeTypeP); |
|
628 |
- } |
|
629 |
- } |
|
630 |
- |
|
631 |
- *(p-1) = '\0'; |
|
632 |
- |
|
633 |
- if (!FileStat(z, &fs)) { |
|
634 |
- ResponseStatusErrno(sessionP); |
|
635 |
- return TRUE; |
|
636 |
- } |
|
637 |
- return ServerDirectoryHandler(sessionP, z, fs.st_mtime, |
|
638 |
- srvP->mimeTypeP); |
|
639 |
- } else |
|
640 |
- return ServerFileHandler(sessionP, z, fs.st_mtime, |
|
641 |
- srvP->mimeTypeP); |
|
642 |
-} |
|
643 |
- |
|
644 |
- |
|
645 |
- |
|
646 |
-static void |
|
647 |
-initUnixStuff(struct _TServer * const srvP) { |
|
648 |
-#ifndef WIN32 |
|
649 |
- srvP->pidfile = srvP->uid = srvP->gid = -1; |
|
650 |
-#endif |
|
651 |
-} |
|
652 |
- |
|
653 |
- |
|
654 |
- |
|
655 |
-static abyss_bool |
|
656 |
-logOpen(struct _TServer * const srvP) { |
|
657 |
- |
|
658 |
- abyss_bool success; |
|
659 |
- |
|
660 |
- success = FileOpenCreate(&srvP->logfile, srvP->logfilename, |
|
661 |
- O_WRONLY | O_APPEND); |
|
662 |
- if (success) { |
|
663 |
- abyss_bool success; |
|
664 |
- success = MutexCreate(&srvP->logmutex); |
|
665 |
- if (success) |
|
666 |
- srvP->logfileisopen = TRUE; |
|
667 |
- else |
|
668 |
- TraceMsg("Can't create mutex for log file"); |
|
669 |
- |
|
670 |
- if (!success) |
|
671 |
- FileClose(&srvP->logfile); |
|
672 |
- } else |
|
673 |
- TraceMsg("Can't open log file '%s'", srvP->logfilename); |
|
674 |
- |
|
675 |
- return success; |
|
676 |
-} |
|
677 |
- |
|
678 |
- |
|
679 |
- |
|
680 |
-static void |
|
681 |
-logClose(struct _TServer * const srvP) { |
|
682 |
- |
|
683 |
- if (srvP->logfileisopen) { |
|
684 |
- FileClose(&srvP->logfile); |
|
685 |
- MutexFree(&srvP->logmutex); |
|
686 |
- srvP->logfileisopen = FALSE; |
|
687 |
- } |
|
688 |
-} |
|
689 |
- |
|
690 |
- |
|
691 |
- |
|
692 |
-static void |
|
693 |
-initSocketStuff(struct _TServer * const srvP, |
|
694 |
- abyss_bool const noAccept, |
|
695 |
- TSocket * const userSocketP, |
|
696 |
- uint16_t const port, |
|
697 |
- const char ** const errorP) { |
|
698 |
- |
|
699 |
- if (userSocketP) { |
|
700 |
- *errorP = NULL; |
|
701 |
- srvP->serverAcceptsConnections = TRUE; |
|
702 |
- srvP->socketBound = TRUE; |
|
703 |
- srvP->listenSocketP = userSocketP; |
|
704 |
- } else if (noAccept) { |
|
705 |
- *errorP = NULL; |
|
706 |
- srvP->serverAcceptsConnections = FALSE; |
|
707 |
- srvP->socketBound = FALSE; |
|
708 |
- } else { |
|
709 |
- *errorP = NULL; |
|
710 |
- srvP->serverAcceptsConnections = TRUE; |
|
711 |
- srvP->socketBound = FALSE; |
|
712 |
- srvP->port = port; |
|
713 |
- } |
|
714 |
- srvP->weCreatedListenSocket = FALSE; |
|
715 |
-} |
|
716 |
- |
|
717 |
- |
|
718 |
- |
|
719 |
-static void |
|
720 |
-createServer(struct _TServer ** const srvPP, |
|
721 |
- abyss_bool const noAccept, |
|
722 |
- TSocket * const userSocketP, |
|
723 |
- uint16_t const portNumber, |
|
724 |
- const char ** const errorP) { |
|
725 |
- |
|
726 |
- struct _TServer * srvP; |
|
727 |
- |
|
728 |
- MALLOCVAR(srvP); |
|
729 |
- |
|
730 |
- if (srvP == NULL) { |
|
731 |
- xmlrpc_asprintf(errorP, |
|
732 |
- "Unable to allocate space for server descriptor"); |
|
733 |
- } else { |
|
734 |
- srvP->terminationRequested = false; |
|
735 |
- |
|
736 |
- initSocketStuff(srvP, noAccept, userSocketP, portNumber, errorP); |
|
737 |
- |
|
738 |
- if (!*errorP) { |
|
739 |
- srvP->defaulthandler = ServerDefaultHandlerFunc; |
|
740 |
- |
|
741 |
- srvP->name = strdup("unnamed"); |
|
742 |
- srvP->filespath = strdup(DEFAULT_DOCS); |
|
743 |
- srvP->logfilename = NULL; |
|
744 |
- srvP->keepalivetimeout = 15; |
|
745 |
- srvP->keepalivemaxconn = 30; |
|
746 |
- srvP->timeout = 15; |
|
747 |
- srvP->advertise = TRUE; |
|
748 |
- srvP->mimeTypeP = NULL; |
|
749 |
- srvP->useSigchld = FALSE; |
|
750 |
- |
|
751 |
- initUnixStuff(srvP); |
|
752 |
- |
|
753 |
- ListInitAutoFree(&srvP->handlers); |
|
754 |
- ListInitAutoFree(&srvP->defaultfilenames); |
|
755 |
- |
|
756 |
- srvP->logfileisopen = FALSE; |
|
757 |
- |
|
758 |
- *errorP = NULL; |
|
759 |
- } |
|
760 |
- if (*errorP) |
|
761 |
- free(srvP); |
|
762 |
- } |
|
763 |
- *srvPP = srvP; |
|
764 |
-} |
|
765 |
- |
|
766 |
- |
|
767 |
- |
|
768 |
-static void |
|
769 |
-setNamePathLog(TServer * const serverP, |
|
770 |
- const char * const name, |
|
771 |
- const char * const filesPath, |
|
772 |
- const char * const logFileName) { |
|
773 |
-/*---------------------------------------------------------------------------- |
|
774 |
- This odd function exists to help with backward compatibility. |
|
775 |
- Today, we have the expandable model where you create a server with |
|
776 |
- default parameters, then use ServerSet... functions to choose |
|
777 |
- non-default parameters. But before, you specified these three |
|
778 |
- parameters right in the arguments of various create functions. |
|
779 |
- if (name) |
|
780 |
- ServerSetName(serverP, name); |
|
781 |
- if (filesPath) |
|
782 |
- ServerSetFilesPath(serverP, filesPath); |
|
783 |
- if (logFileName) |
|
784 |
- ServerSetLogFileName(serverP, logFileName); |
|
785 |
-} |
|
786 |
- |
|
787 |
- |
|
788 |
- |
|
789 |
-abyss_bool |
|
790 |
-ServerCreate(TServer * const serverP, |
|
791 |
- const char * const name, |
|
792 |
- uint16_t const portNumber, |
|
793 |
- const char * const filesPath, |
|
794 |
- const char * const logFileName) { |
|
795 |
- |
|
796 |
- abyss_bool const noAcceptFalse = FALSE; |
|
797 |
- |
|
798 |
- abyss_bool success; |
|
799 |
- const char * error; |
|
800 |
- |
|
801 |
- createServer(&serverP->srvP, noAcceptFalse, NULL, portNumber, &error); |
|
802 |
- |
|
803 |
- if (error) { |
|
804 |
- TraceMsg(error); |
|
805 |
- xmlrpc_strfree(error); |
|
806 |
- success = FALSE; |
|
807 |
- } else { |
|
808 |
- success = TRUE; |
|
809 |
- |
|
810 |
- setNamePathLog(serverP, name, filesPath, logFileName); |
|
811 |
- } |
|
812 |
- |
|
813 |
- return success; |
|
814 |
-} |
|
815 |
- |
|
816 |
- |
|
817 |
- |
|
818 |
-static void |
|
819 |
-createSocketFromOsSocket(TOsSocket const osSocket, |
|
820 |
- TSocket ** const socketPP) { |
|
821 |
- |
|
822 |
-#ifdef WIN32 |
|
823 |
- SocketWinCreateWinsock(osSocket, socketPP); |
|
824 |
-#else |
|
825 |
- SocketUnixCreateFd(osSocket, socketPP); |
|
826 |
-#endif |
|
827 |
-} |
|
828 |
- |
|
829 |
- |
|
830 |
- |
|
831 |
-abyss_bool |
|
832 |
-ServerCreateSocket(TServer * const serverP, |
|
833 |
- const char * const name, |
|
834 |
- TOsSocket const socketFd, |
|
835 |
- const char * const filesPath, |
|
836 |
- const char * const logFileName) { |
|
837 |
- |
|
838 |
- abyss_bool success; |
|
839 |
- TSocket * socketP; |
|
840 |
- |
|
841 |
- createSocketFromOsSocket(socketFd, &socketP); |
|
842 |
- |
|
843 |
- if (socketP) { |
|
844 |
- abyss_bool const noAcceptFalse = FALSE; |
|
845 |
- |
|
846 |
- const char * error; |
|
847 |
- |
|
848 |
- createServer(&serverP->srvP, noAcceptFalse, socketP, 0, &error); |
|
849 |
- |
|
850 |
- if (error) { |
|
851 |
- TraceMsg(error); |
|
852 |
- success = FALSE; |
|
853 |
- xmlrpc_strfree(error); |
|
854 |
- } else { |
|
855 |
- success = TRUE; |
|
856 |
- |
|
857 |
- setNamePathLog(serverP, name, filesPath, logFileName); |
|
858 |
- } |
|
859 |
- } else |
|
860 |
- success = FALSE; |
|
861 |
- |
|
862 |
- return success; |
|
863 |
-} |
|
864 |
- |
|
865 |
- |
|
866 |
- |
|
867 |
-abyss_bool |
|
868 |
-ServerCreateNoAccept(TServer * const serverP, |
|
869 |
- const char * const name, |
|
870 |
- const char * const filesPath, |
|
871 |
- const char * const logFileName) { |
|
872 |
- |
|
873 |
- abyss_bool const noAcceptTrue = TRUE; |
|
874 |
- |
|
875 |
- abyss_bool success; |
|
876 |
- const char * error; |
|
877 |
- |
|
878 |
- createServer(&serverP->srvP, noAcceptTrue, NULL, 0, &error); |
|
879 |
- |
|
880 |
- if (error) { |
|
881 |
- TraceMsg(error); |
|
882 |
- success = FALSE; |
|
883 |
- xmlrpc_strfree(error); |
|
884 |
- } else { |
|
885 |
- success = TRUE; |
|
886 |
- |
|
887 |
- setNamePathLog(serverP, name, filesPath, logFileName); |
|
888 |
- } |
|
889 |
- return success; |
|
890 |
-} |
|
891 |
- |
|
892 |
- |
|
893 |
- |
|
894 |
-void |
|
895 |
-ServerCreateSocket2(TServer * const serverP, |
|
896 |
- TSocket * const socketP, |
|
897 |
- const char ** const errorP) { |
|
898 |
- |
|
899 |
- abyss_bool const noAcceptFalse = FALSE; |
|
900 |
- |
|
901 |
- assert(socketP); |
|
902 |
- |
|
903 |
- createServer(&serverP->srvP, noAcceptFalse, socketP, 0, errorP); |
|
904 |
-} |
|