1 /*
2 handlers.c
3 This file is part of pserv
4 http://pserv.sourceforge.net
5
6 Copyright (c) 2001-2002-2003-2004 Riccardo Mottola. All rights reserved.
7 mail: rmottola@users.sourceforge.net
8
9 This file is free software, released under GPL. Please read acclosed license
10 */
11
12 #include <errno.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <assert.h>
16
17 #include "handlers.h"
18 #include "log.h"
19 #include "main.h"
20 #include "mime.h"
21
22 #ifdef AUTO_INDEX
23 #include <dirent.h>
24 #include <time.h>
25 #endif
26
27 extern char cgiRoot[MAX_PATH_LEN+1]; /* root for CGI scripts exec */
28 extern char homePath[MAX_PATH_LEN+1]; /* root for PHP scripts exec */
29 extern int port; /* server port */
30 extern char defaultFileName[MAX_PATH_LEN+1]; /* default name for index, default or similar file */
31
sendChunk(sock,buff,len)32 int sendChunk(sock, buff, len)
33 int sock;
34 char *buff;
35 int len;
36 {
37 register int sockSent;
38 int totalSent;
39
40 totalSent = 0;
41
42 if ((sockSent = send(sock, buff, len, 0)) < len )
43 {
44 if (sockSent < 0)
45 {
46 if (errno == EAGAIN)
47 {
48 sockSent = 0;
49 DBGPRINTF(("output resource temporarily not available (1st cycle)\n"));
50 } else if (errno == EPIPE)
51 {
52 printf("broken pipe during raw out\n");
53 return -1;
54 } else if (errno == EBADF)
55 {
56 DBGPRINTF(("invalid out descriptor\n"));
57 return -1;
58 }
59 else
60 DBGPRINTF(("error during raw sock writing! %d\n", errno));
61 }
62 totalSent += sockSent;
63 while (totalSent < len)
64 {
65 if ((sockSent = send(sock, buff+totalSent, len-totalSent, 0)) < len - totalSent)
66 {
67 if (sockSent < 0)
68 {
69 if (errno == EAGAIN)
70 {
71 sockSent = 0;
72 DBGPRINTF(("output resource temporarily not available\n"));
73 } else if (errno == EPIPE)
74 {
75 DBGPRINTF(("broken pipe during raw out\n"));
76 return -1;
77 } else if (errno == EBADF)
78 {
79 DBGPRINTF(("invalid out descriptor\n"));
80 return -1;
81 } else
82 {
83 DBGPRINTF(("error during raw sock writing! %d\n", errno));
84 return -1;
85 }
86 }
87 }
88 totalSent += sockSent;
89 } /* while */
90 }
91 return len;
92 }
93
94 #ifdef ENABLE_CGI
cgiHandler(port,sock,req,postStr)95 int cgiHandler(port, sock, req, postStr)
96 int port;
97 int sock;
98 struct request req;
99 char *postStr;
100 {
101 char *envPath;
102 char *relativePath;
103 char completedPath[2*MAX_PATH_LEN+1]; /* documentAddress + cgiRoot */
104 char scriptWorkingDir[2*MAX_PATH_LEN+1];
105 char **newArgv;
106 char **newEnvp;
107 int i;
108 int outStdPipe[2]; /* we will redirect the script output to a pipe so we can read it */
109 int inStdPipe[2]; /* we will redirect the script input to a pipe so we can read it */
110 int pid; /* we fork and execute inside the child the script */
111 char pipeReadBuf[PIPE_READ_BUF+1];
112 int howMany;
113 int totalSentFromPipe; /* amount of bytes sucked from the pipe and pushed in to the socket */
114 int fatal;
115
116
117 /* constructing script paths */
118 /* we assume the CGI_MATCH_STRING is stricly at the beginning */
119 relativePath = &(req.documentAddress[strlen(CGI_MATCH_STRING) - 1]);
120 strcpy(completedPath, cgiRoot);
121 strcat(completedPath, relativePath);
122
123 /* reconstruct where the script will be running */
124 strcpy(scriptWorkingDir, completedPath);
125 i = strlen(scriptWorkingDir);
126 howMany = strlen(cgiRoot);
127 while (i > howMany && scriptWorkingDir[i] != '/')
128 i--;
129 scriptWorkingDir[i] = '\0';
130 DBGPRINTF(("script working dir: %s \n", scriptWorkingDir));
131
132 /* we check if we are trying to execute a directory... or a non existent or not accessible file */
133 {
134 struct stat fileStats;
135
136 if (completedPath[strlen(completedPath)-1] == '/')
137 {
138 sayError(sock, FORBIDDEN, req.documentAddress, req);
139 return -1;
140 }
141
142 if (stat(completedPath, &fileStats) < 0)
143 { /* the file doesn't exist ot some other error, we don't worry more about it */
144 sayError(sock, NOT_FOUND, req.documentAddress, req);
145 return -1;
146 } else if ((fileStats.st_mode & S_IFDIR) == S_IFDIR)
147 {
148 sayError(sock, FORBIDDEN, req.documentAddress, req);
149 return -1;
150 }
151 }
152
153 /* first we create the pipes needed for stdout redirection */
154 if (pipe(outStdPipe))
155 {
156 DBGPRINTF(("Pipe creation error\n"));
157 return -1;
158 }
159 if (pipe(inStdPipe))
160 {
161 DBGPRINTF(("Pipe creation error\n"));
162 return -1;
163 }
164
165
166 /* now we fork to subsequently execve */
167 pid = fork();
168 if (pid)
169 { /* this is the parent process */
170 if (pid < 0)
171 { /* we check for creation error */
172 printf ("Forking error during cgi exec: %d\n", errno);
173 return -1;
174 }
175 /* we close the unused end of the pipe */
176 close(outStdPipe[WRITE]);
177 close(inStdPipe[READ]);
178
179 /* check if method is POST */
180 if (req.method[0]=='P' && req.method[1]=='O' && req.method[2]=='S' && req.method[3]=='T' && req.method[4]=='\0')
181 {
182 /* we have to feed the stdin of the script */
183 if(!strlen(postStr))
184 {
185 DBGPRINTF(("cannot post empty data\n"));
186 return -1;
187 }
188 howMany = write(inStdPipe[WRITE], postStr, strlen(postStr));
189 if (howMany < 0)
190 DBGPRINTF(("Error during script pipe read (POST).\n"));
191 }
192 totalSentFromPipe = 0;
193 fatal = NO;
194 howMany = 1;
195 while (howMany > 0 && !fatal)
196 {
197 howMany = read(outStdPipe[READ], pipeReadBuf, PIPE_READ_BUF);
198 if (howMany > 0)
199 {
200 if (sendChunk(sock, pipeReadBuf, howMany) < 0)
201 fatal = YES;
202 else
203 totalSentFromPipe += howMany;
204 } else
205 fatal = YES; /* it may be EOF too */
206 }
207 /* now we finished and we clean up */
208 wait(&i);
209 if (i) /* check if execution exited cleanly or with code */
210 logWriter(LOG_CGI_FAILURE, NULL, 0, req, i);
211 else
212 logWriter(LOG_CGI_SUCCESS, NULL, totalSentFromPipe, req, 0);
213 close(outStdPipe[READ]);
214 close(inStdPipe[WRITE]);
215 } else
216 { /* this is the child process */
217 /* now we do some environment setup work */
218 newArgv = (char **)calloc(MAX_ARGV_LEN + 1, sizeof(char*));
219 for (i = 0; i < MAX_ENVP_LEN + 1; i++)
220 {
221 newArgv[i] = calloc(MAX_PATH_LEN, sizeof(char));
222 }
223
224 newEnvp = (char **)calloc(MAX_ENVP_LEN + 1, sizeof(char*));
225
226
227
228 i = 0;
229 strcpy(newArgv[i++], &relativePath[1]); /* here we should pass the progname */
230 if (strlen(req.queryString))
231 {
232 int toParse;
233 int j, k;
234
235 toParse = YES;
236 j = strlen(req.queryString);
237 while (toParse && j > 0)
238 {
239 if (req.queryString[j] == '=')
240 toParse = NO;
241 j--;
242 }
243 if (toParse)
244 {
245 j = 0;
246 k = 0;
247 howMany = strlen(req.queryString);
248 while (j < howMany)
249 {
250 if (req.queryString[j] == '+')
251 {
252 newArgv[i++][k] = '\0';
253 k = 0;
254 } else
255 newArgv[i][k++] = req.queryString[j];
256 j++;
257 }
258 i++; /* after all we will have at least one argument! */
259 }
260 }
261 newArgv[i] = NULL; /* we correctly terminate argv */
262
263 i = 0;
264 /* beware of not overfilling this array, check MAX_ENVP_LEN */
265 if (req.contentLength != -1)
266 {
267 newEnvp[i] = (char *) calloc(35, sizeof(char));
268 sprintf(newEnvp[i++], "CONTENT_LENGTH=%ld", req.contentLength);
269 newEnvp[i] = (char *) calloc(CONTENT_TYPE_LEN + 14, sizeof(char));
270 strcpy(newEnvp[i], "CONTENT_TYPE=");
271 strcat(newEnvp[i++], req.contentType);
272 }
273 newEnvp[i] = (char *) calloc(strlen(DEFAULT_SERVER_NAME) + 13, sizeof(char));
274 strcpy(newEnvp[i], "SERVER_NAME=");
275 strcat(newEnvp[i++], DEFAULT_SERVER_NAME);
276 newEnvp[i] = (char *) calloc(128, sizeof(char));
277 strcpy(newEnvp[i], "SERVER_SOFTWARE=");
278 strcat(newEnvp[i], SERVER_SOFTWARE_STR);
279 strcat(newEnvp[i], "/");
280 strcat(newEnvp[i++], SERVER_VERSION_STR);
281 newEnvp[i] = (char *) calloc(METHOD_LEN+16, sizeof(char));
282 strcpy(newEnvp[i], "REQUEST_METHOD=");
283 strcat(newEnvp[i++], req.method);
284 newEnvp[i] = (char *) calloc(MAX_PATH_LEN+16, sizeof(char));
285 strcpy(newEnvp[i], "SCRIPT_NAME=");
286 strcat(newEnvp[i++], req.documentAddress);
287 newEnvp[i] = (char *) calloc(32, sizeof(char));
288 strcpy(newEnvp[i], "GATEWAY_INTERFACE=");
289 strcat(newEnvp[i++], CGI_VERSION);
290 newEnvp[i] = (char *) calloc(18, sizeof(char));
291 sprintf(newEnvp[i++], "SERVER_PORT=%d", port);
292 newEnvp[i] = (char *) calloc(MAX_QUERY_STRING_LEN+16, sizeof(char));
293 strcpy(newEnvp[i], "QUERY_STRING=");
294 strcat(newEnvp[i++], req.queryString);
295 newEnvp[i] = (char *) calloc(PROTOCOL_LEN+17, sizeof(char));
296 strcpy(newEnvp[i], "SERVER_PROTOCOL=");
297 strcat(newEnvp[i++], req.protocolVersion);
298 newEnvp[i] = (char *) calloc(ADDRESS_LEN+13, sizeof(char));
299 strcpy(newEnvp[i], "REMOTE_ADDR=");
300 strcat(newEnvp[i++], req.address);
301 newEnvp[i] = (char *) calloc(USER_AGENT_LEN+17, sizeof(char));
302 strcpy(newEnvp[i], "HTTP_USER_AGENT=");
303 strcat(newEnvp[i++], req.userAgent);
304 newEnvp[i] = (char *) calloc(MAX_PATH_LEN+17, sizeof(char));
305 completedPath[MAX_PATH_LEN]='\0';
306 strcpy(newEnvp[i], "SCRIPT_FILENAME=");
307 strcat(newEnvp[i++], completedPath);
308 if (req.cookie[0] != '\0')
309 {
310 newEnvp[i] = (char *) calloc(MAX_COOKIE_LEN+13, sizeof(char));
311 strcpy(newEnvp[i], "HTTP_COOKIE=");
312 strcat(newEnvp[i++], req.cookie);
313 }
314
315 /* extracting PATH env variable */
316 envPath = getenv("PATH");
317 /* we get the path from the env itself so we assume it safe */
318 newEnvp[i] = (char *) calloc(MAX_PATH_LEN+16, sizeof(char));
319 strcpy(newEnvp[i], "PATH=");
320 strcat(newEnvp[i++], envPath);
321
322 /* terminate the array */
323 newEnvp[i] = NULL;
324
325 /* we change the current working directory to the scripts one */
326 if(chdir(scriptWorkingDir))
327 {
328 DBGPRINTF(("error while changing PWD in script execution: %d\n", errno));
329 }
330
331 close(outStdPipe[READ]); /* we close the unused end*/
332 dup2(outStdPipe[WRITE], 1); /* we duplicate the pipe to the stdout */
333 close(outStdPipe[WRITE]); /* we close the pipe, since we use the duplicate */
334
335 close(inStdPipe[WRITE]); /* we close the unused end*/
336 dup2(inStdPipe[READ], 0); /* we duplicate the pipe to the stdin */
337 close(inStdPipe[READ]); /* we close the pipe, since we use the duplicate */
338
339
340 /* generate a reduced mimeHeader, no type, no size, etc */
341 generateMimeHeader(sock, 200, "", NULL, req.protocolVersion, CGI_ONLY_HEADER);
342
343 /* now we execute the script replacing the current child */
344 execve(completedPath, newArgv, newEnvp);
345 /* we reach this line only if an execution error occoured */
346 /* logging will happen in the father */
347 printf("\n<HTML><HEAD><TITLE>CGI Error</TITLE></HEAD><BODY><H1>CGI Exec error</H1></BODY></HTML>\n");
348 exit(-1);
349 }
350 return 0;
351 }
352 #endif /* ENABLE_CGI */
353
354 #ifdef PHP
phpHandler(port,sock,phpFileName,completedPath,req,postStr)355 int phpHandler(port, sock, phpFileName, completedPath, req, postStr)
356 int port;
357 int sock;
358 char *phpFileName;
359 char *completedPath;
360 struct request req;
361 char *postStr;
362 {
363 char *envPath; /* pointer to the envrionment PATH variable */
364 char *relativePath;
365 char scriptWorkingDir[2*MAX_PATH_LEN+1];
366 char **newArgv;
367 char **newEnvp;
368 int i;
369 int outStdPipe[2]; /* we will redirect the script output to a pipe so we can read it */
370 int inStdPipe[2]; /* we will redirect the script input to a pipe so we can read it */
371 int pid; /* we fork and execute inside the child the script */
372 char pipeReadBuf[PIPE_READ_BUF+1];
373 int howMany;
374 int totalSentFromPipe; /* ampunt of bytes sucked from the pipe and pushed in to the socket */
375 int fatal;
376
377 relativePath = strrchr(completedPath, '/');
378 strncpy(scriptWorkingDir, completedPath, strlen(completedPath) - strlen(relativePath));
379 scriptWorkingDir[strlen(completedPath) - strlen(relativePath)] = '\0';
380
381 /* first we create the pipes needed for stdout redirection */
382 if (pipe(outStdPipe))
383 {
384 DBGPRINTF(("Pipe creation error\n"));
385 return -1;
386 }
387 if (pipe(inStdPipe))
388 {
389 DBGPRINTF(("Pipe creation error\n"));
390 return -1;
391 }
392
393
394 /* now we fork to subsequently execve */
395 pid = fork();
396 if (pid)
397 { /* this is the parent process */
398 if (pid < 0)
399 { /* we check for creation error */
400 DBGPRINTF(("Forking error during cgi exec: %d\n", errno));
401 return -1;
402 }
403 /* we close the unused end of the pipe */
404 close(outStdPipe[WRITE]);
405 close(inStdPipe[READ]);
406
407 if (req.method[0]=='P' && req.method[1]=='O' && req.method[2]=='S' && req.method[3]=='T' && req.method[4]=='\0')
408 {
409 /* we have to feed the stdin of the script */
410 if(!strlen(postStr))
411 {
412 DBGPRINTF(("cannot post empty data\n"));
413 return -1;
414 }
415 howMany = write(inStdPipe[WRITE], postStr, strlen(postStr));
416 if (howMany < 0)
417 DBGPRINTF(("Error during script pipe read (POST).\n"));
418 }
419 totalSentFromPipe = 0;
420 fatal = NO;
421 howMany = 1;
422 while (howMany > 0 && !fatal)
423 {
424 howMany = read(outStdPipe[READ], pipeReadBuf, PIPE_READ_BUF);
425 if (howMany > 0)
426 {
427 if (sendChunk(sock, pipeReadBuf, howMany) < 0)
428 fatal = YES;
429 else
430 totalSentFromPipe += howMany;
431 } else
432 fatal = YES; /* it may be EOF too */
433 }
434 /* now we finished and we clean up */
435 wait(&i);
436 if (i) /* check if execution exited cleanly or with code */
437 logWriter(LOG_CGI_FAILURE, NULL, 0, req, i);
438 else
439 logWriter(LOG_CGI_SUCCESS, NULL, totalSentFromPipe, req, 0);
440 close(outStdPipe[READ]);
441 close(inStdPipe[WRITE]);
442 } else
443 { /* this is the child process */
444 /* now we do some environment setup work */
445 newArgv = (char **)calloc(MAX_ARGV_LEN + 1, sizeof(char*));
446 for (i = 0; i < MAX_ARGV_LEN + 1; i++)
447 {
448 newArgv[i] = (char *)calloc(MAX_PATH_LEN, sizeof(char));
449 }
450
451 newEnvp = (char **)calloc(MAX_ENVP_LEN + 1, sizeof(char*));
452
453 i = 0;
454 strcpy(newArgv[i++], phpFileName); /* here we should pass the phppath */
455 strcpy(newArgv[i++], completedPath); /* here we should pass the scriptpath */
456 if (strlen(req.queryString))
457 {
458 int toParse;
459 int j, k;
460
461 toParse = YES;
462 j = strlen(req.queryString);
463 while (toParse && j > 0)
464 {
465 if (req.queryString[j] == '=')
466 toParse = NO;
467 j--;
468 }
469 if (toParse)
470 {
471 j = 0;
472 k = 0;
473 howMany = strlen(req.queryString);
474 while (j < howMany)
475 {
476 if (req.queryString[j] == '+')
477 {
478 newArgv[i++][k] = '\0';
479 k = 0;
480 } else
481 newArgv[i][k++] = req.queryString[j];
482 j++;
483 }
484 i++; /* after all we will have at least one argument! */
485 }
486 }
487 newArgv[i] = NULL; /* we correctly terminate argv */
488
489 i = 0;
490 /* beware of not overfilling this array, check MAX_ENVP_LEN */
491 if (req.contentLength != -1)
492 {
493 newEnvp[i] = (char *) calloc(35, sizeof(char));
494 sprintf(newEnvp[i++], "CONTENT_LENGTH=%ld", req.contentLength);
495 newEnvp[i] = (char *) calloc(CONTENT_TYPE_LEN + 14, sizeof(char));
496 strcpy(newEnvp[i], "CONTENT_TYPE=");
497 strcat(newEnvp[i++], req.contentType);
498 }
499 newEnvp[i] = (char *) calloc(strlen(DEFAULT_SERVER_NAME) + 13, sizeof(char));
500 strcpy(newEnvp[i], "SERVER_NAME=");
501 strcat(newEnvp[i++], DEFAULT_SERVER_NAME);
502 newEnvp[i] = (char *) calloc(128, sizeof(char));
503 strcpy(newEnvp[i], "SERVER_SOFTWARE=");
504 strcat(newEnvp[i], SERVER_SOFTWARE_STR);
505 strcat(newEnvp[i], "/");
506 strcat(newEnvp[i++], SERVER_VERSION_STR);
507 newEnvp[i] = (char *) calloc(METHOD_LEN+16, sizeof(char));
508 strcpy(newEnvp[i], "REQUEST_METHOD=");
509 strcat(newEnvp[i++], req.method);
510 newEnvp[i] = (char *) calloc(MAX_PATH_LEN+16, sizeof(char));
511 strcpy(newEnvp[i], "SCRIPT_NAME=");
512 strcat(newEnvp[i++], req.documentAddress);
513 newEnvp[i] = (char *) calloc(32, sizeof(char));
514 strcpy(newEnvp[i], "GATEWAY_INTERFACE=");
515 strcat(newEnvp[i++], CGI_VERSION);
516 newEnvp[i] = (char *) calloc(18, sizeof(char));
517 sprintf(newEnvp[i++], "SERVER_PORT=%d", port);
518 newEnvp[i] = (char *) calloc(MAX_QUERY_STRING_LEN+16, sizeof(char));
519 strcpy(newEnvp[i], "QUERY_STRING=");
520 strcat(newEnvp[i++], req.queryString);
521 newEnvp[i] = (char *) calloc(PROTOCOL_LEN+17, sizeof(char));
522 strcpy(newEnvp[i], "SERVER_PROTOCOL=");
523 strcat(newEnvp[i++], req.protocolVersion);
524 newEnvp[i] = (char *) calloc(ADDRESS_LEN+13, sizeof(char));
525 strcpy(newEnvp[i], "REMOTE_ADDR=");
526 strcat(newEnvp[i++], req.address);
527 newEnvp[i] = (char *) calloc(USER_AGENT_LEN+17, sizeof(char));
528 strcpy(newEnvp[i], "HTTP_USER_AGENT=");
529 strcat(newEnvp[i++], req.userAgent);
530 newEnvp[i] = (char *) calloc(MAX_PATH_LEN+17, sizeof(char));
531 completedPath[MAX_PATH_LEN]='\0';
532 strcpy(newEnvp[i], "SCRIPT_FILENAME=");
533 strcat(newEnvp[i++], completedPath);
534 if (req.cookie[0] != '\0')
535 {
536 newEnvp[i] = (char *) calloc(MAX_COOKIE_LEN+13, sizeof(char));
537 strcpy(newEnvp[i], "HTTP_COOKIE=");
538 strcat(newEnvp[i++], req.cookie);
539 }
540
541 /* extracting PATH env variable */
542 envPath = getenv("PATH");
543 /* we get the path from the env itself so we assume it safe */
544 newEnvp[i] = (char *) calloc(MAX_PATH_LEN+16, sizeof(char));
545 strcpy(newEnvp[i], "PATH=");
546 strcat(newEnvp[i++], envPath);
547
548 /* terminate the array */
549 newEnvp[i] = NULL;
550
551 /* we change the current working directory to the scripts one */
552 if(chdir(scriptWorkingDir))
553 {
554 DBGPRINTF(("error while changing PWD in script execution: %d\n", errno));
555 }
556
557 close(outStdPipe[READ]); /* we close the unused end*/
558 dup2(outStdPipe[WRITE], 1); /* we duplicate the pipe to the stdout */
559 close(outStdPipe[WRITE]); /* we close the pipe, since we use the duplicate */
560
561 close(inStdPipe[WRITE]); /* we close the unused end*/
562 dup2(inStdPipe[READ], 0); /* we duplicate the pipe to the stdin */
563 close(inStdPipe[READ]); /* we close the pipe, since we use the duplicate */
564
565
566 /* generate a reduced mimeHeader, no type, no size, etc */
567 generateMimeHeader(sock, 200, "", NULL, req.protocolVersion, CGI_ONLY_HEADER);
568
569 /* now we execute the script replacing the current child */
570 execve(phpFileName, newArgv, newEnvp);
571 /* we reach this line only if an execution error occoured */
572 /* logging will happen in the father */
573 printf("\n<HTML><HEAD><TITLE>PHP Error</TITLE></HEAD><BODY><H1>PHP Exec error</H1></BODY></HTML>\n");
574 exit(-1);
575 }
576 return 0;
577 }
578 #endif
579
580
581 /* generate a full header for a given file */
dumpHeader(port,sock,filePath,mimeType,req)582 int dumpHeader(port, sock, filePath, mimeType, req)
583 int port;
584 int sock;
585 char filePath[];
586 char mimeType[];
587 struct request req;
588 {
589 FILE *inFile;
590 struct stat fileStats;
591 int sentBytes;
592
593 /* we reconstruct a partial filepath so to include the index file instead of / */
594 inFile = fopen(filePath, "r");
595 if (inFile == NULL) {
596 sayError(sock, NOT_FOUND, req.documentAddress, req);
597 return -1;
598 }
599 stat(filePath, &fileStats);
600 sentBytes = generateMimeHeader(sock, 200, mimeType, &fileStats, req.protocolVersion, FULL_HEADER);
601 logWriter(LOG_HEAD_SUCCESS, req.documentAddress, (long int)sentBytes, req, 0);
602
603 fclose(inFile);
604 return 0;
605 }
606
607
dumpFile(sock,filePath,mimeType,req)608 int dumpFile(sock, filePath, mimeType, req)
609 int sock;
610 char filePath[];
611 char mimeType[];
612 struct request req;
613 {
614 FILE *inFile;
615 struct stat fileStats;
616 char outBuff[OUT_SOCK_BUFF_SIZE+1];
617 int howMany;
618 int fatal;
619
620 inFile = fopen(filePath, "r");
621 if (inFile == NULL) {
622 DBGPRINTF(("File not found.\n"));
623 sayError(sock, NOT_FOUND, req.documentAddress, req);
624 return -1;
625 }
626 stat(filePath, &fileStats);
627 generateMimeHeader(sock, 200, mimeType, &fileStats, req.protocolVersion, FULL_HEADER);
628 logWriter(LOG_GET_SUCCESS, req.documentAddress, (long int)fileStats.st_size, req, 0);
629 howMany = 0;
630
631 if (strncmp(mimeType, "text", 4)) /* check if it is a text type */
632 { /* raw binary output routine */
633 fatal = NO;
634 while(!feof(inFile) && !fatal)
635 {
636 howMany = fread (outBuff, sizeof(char), OUT_SOCK_BUFF_SIZE, inFile);
637 if (howMany > 0)
638 if (sendChunk(sock, outBuff, howMany) < 0)
639 fatal = YES;
640 }
641 } else
642 { /* TEXT output routine */
643 fatal = NO;
644 while(!feof(inFile) && !fatal)
645 {
646 howMany = fread (outBuff, sizeof(char), OUT_SOCK_BUFF_SIZE, inFile);
647 if (howMany > 0)
648 {
649 #ifdef ON_THE_FLY_CONVERSION
650 {
651 int i;
652 for (i = 0; i < howMany; i++)
653 if(outBuff[i] == '\r') outBuff[i] = '\n';
654 }
655 #endif
656 if (sendChunk(sock, outBuff, howMany) < 0)
657 fatal = YES;
658 }
659 }
660 }
661 fclose(inFile);
662 return 0;
663 }
664
665
666 #ifdef AUTO_INDEX
generateIndex(sock,dirPath,mimeType,req)667 int generateIndex(sock, dirPath, mimeType, req)
668 int sock;
669 char dirPath[];
670 char mimeType[];
671 struct request req;
672 {
673 struct stat fileStats;
674 struct dirent *dp;
675 DIR *dfd;
676 char indexFilePath[MAX_PATH_LEN+1];
677 FILE *tempFile;
678 size_t generatedBytes;
679 char tempStr[MAX_PATH_LEN+1];
680 char linkStr[MAX_PATH_LEN+1];
681 char linkPath[MAX_PATH_LEN+1];
682 time_t currTime;
683 char timeStr[256];
684
685 currTime = time(NULL);
686 strftime(timeStr, 256, "%a, %d %b %Y %H:%M:%S %Z", (struct tm *) localtime(&currTime));
687
688 /* first we chek if an index does already exist, in case we exit with 1 */
689 strcpy(indexFilePath, dirPath);
690 strcat(indexFilePath, defaultFileName);
691 if (stat(indexFilePath, &fileStats))
692 {
693 if (errno == EACCES)
694 return -1; /* the index file exists but we have no access */
695 } else
696 return -1; /* the index file exists */
697
698 /* the directory is without the trailing slash */
699 /* I don't feel like allocating another string */
700 dirPath[strlen(dirPath)-1]='\0';
701 if ((dfd = opendir(dirPath)) == NULL)
702 {
703 DBGPRINTF(("Can't open dir: %s\n", dirPath));
704 return 1;
705 }
706 dirPath[strlen(dirPath)]='/'; /* we put the slash back in */
707
708 /* now we get a tempfile where to store the created index, so we can at the end know its length */
709 tempFile = tmpfile();
710 generatedBytes = 0;
711 strcpy(tempStr, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n<HTML><HEAD><TITLE>");
712 strcat(tempStr, req.documentAddress);
713 strcat(tempStr, "</TITLE></HEAD>\n");
714 generatedBytes += strlen(tempStr);
715 fprintf(tempFile, "%s", tempStr);
716
717 sprintf(tempStr, "<BODY><H1>Index of: %s </H1> ", req.documentAddress);
718 strcat(tempStr, "\n");
719 generatedBytes += strlen(tempStr);
720 fprintf(tempFile, "%s", tempStr);
721
722 sprintf(tempStr, "<HR><P><I>Date: %s</I></P><HR>", timeStr);
723 strcat(tempStr, "<BLOCKQUOTE>\n");
724 generatedBytes += strlen(tempStr);
725 fprintf(tempFile, "%s", tempStr);
726
727 /* now we read the directory entries */
728 while ((dp = readdir(dfd)) != NULL)
729 {
730 char dirToStat[MAX_PATH_LEN+1]; /* temporary directory to stat on */
731 if (strcmp(dp->d_name, ".")) /* not self */
732 {
733 if (strcmp(dp->d_name, ".."))
734 strcpy(linkStr, dp->d_name);
735 else
736 strcpy(linkStr, "Parent Directory");
737 strcpy(linkPath, dp->d_name);
738
739 /* now we check if the entry is a dir */
740 strcpy(dirToStat, dirPath);
741 strcat(dirToStat, dp->d_name);
742 stat(dirToStat, &fileStats);
743 if ((fileStats.st_mode & S_IFMT) == S_IFDIR)
744 {
745 /* so it is a directory */
746 sprintf(tempStr, "<A HREF=\"%s/\">%s/</A><BR>\n", dp->d_name, linkStr);
747 } else
748 {
749 char fileSize[32];
750 off_t byteSize;
751
752 byteSize = fileStats.st_size;
753 if (byteSize < 1024)
754 sprintf(fileSize, "%d bytes", (int) byteSize);
755 else if (byteSize < 1024*1024)
756 sprintf(fileSize, "%1.2f Kbytes", (float) byteSize / 1024);
757 else
758 sprintf(fileSize, "%1.2f Mbytes", (float) byteSize / (1024*1024));
759
760 sprintf(tempStr, "<A HREF=\"%s\">%s</A> (%s)<BR>\n", dp->d_name, linkStr, fileSize);
761 }
762
763 generatedBytes += strlen(tempStr);
764 fprintf(tempFile, "%s", tempStr);
765 }
766 }
767 strcpy(tempStr, "</BLOCKQUOTE>\n");
768 generatedBytes += strlen(tempStr);
769 fprintf(tempFile, "%s", tempStr);
770 sprintf(tempStr, "<HR><P ALIGN=\"RIGHT\">pico Server %s</P></HTML>\n", SERVER_VERSION_STR);
771 generatedBytes += strlen(tempStr);
772 fprintf(tempFile, "%s", tempStr);
773
774 /* we rewind the temporary file */
775 fseek(tempFile, (long) 0, SEEK_SET);
776 clearerr(tempFile);
777
778 /* now let's fake some statistics */
779 fileStats.st_size = generatedBytes;
780 fileStats.st_mtime = currTime;
781 generateMimeHeader(sock, 200, "text/html", &fileStats, req.protocolVersion, FULL_HEADER);
782 logWriter(LOG_GET_SUCCESS, req.documentAddress, (long int)generatedBytes, req, 0);
783
784 /* now we output it */
785 {
786 int howMany;
787 int fatal;
788 char outBuff[OUT_SOCK_BUFF_SIZE+1];
789
790 howMany = 0;
791 fatal = NO;
792 while(!feof(tempFile) && !fatal)
793 {
794 howMany = fread (outBuff, sizeof(char), OUT_SOCK_BUFF_SIZE, tempFile);
795 if (howMany > 0)
796 if (sendChunk(sock, outBuff, howMany) < 0)
797 fatal = YES;
798 }
799 }
800
801 fclose(tempFile);
802 return 0;
803 }
804 #endif
805