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