aboutsummaryrefslogtreecommitdiff
path: root/www/pserv
diff options
context:
space:
mode:
authorNorikatsu Shigemura <nork@FreeBSD.org>2003-10-17 08:11:55 +0000
committerNorikatsu Shigemura <nork@FreeBSD.org>2003-10-17 08:11:55 +0000
commit148e621cf93c5996d66f69a43ed8e95e985439ff (patch)
tree3c1c6f9533ea58f6b3ec476deef054fb9d5f0d04 /www/pserv
parentab6dc456b9e0b7b9d7ebb098ad4061431a8b3dd1 (diff)
downloadports-148e621cf93c5996d66f69a43ed8e95e985439ff.tar.gz
ports-148e621cf93c5996d66f69a43ed8e95e985439ff.zip
Add pserv 3.0.b1, a portable and small webserver written in C.
PR: ports/58119 Submitted by: Alex Dupre <sysadmin@alexdupre.com>
Notes
Notes: svn path=/head/; revision=91495
Diffstat (limited to 'www/pserv')
-rw-r--r--www/pserv/Makefile32
-rw-r--r--www/pserv/distinfo1
-rw-r--r--www/pserv/files/patch-Makefile17
-rw-r--r--www/pserv/files/patch-handlers.c362
-rw-r--r--www/pserv/files/patch-handlers.h10
-rw-r--r--www/pserv/files/patch-main.c386
-rw-r--r--www/pserv/files/patch-main.h65
-rw-r--r--www/pserv/files/patch-mime.c34
-rw-r--r--www/pserv/files/patch-mime_types.dat7
-rw-r--r--www/pserv/files/patch-pserv.conf18
-rw-r--r--www/pserv/files/pserv.sh25
-rw-r--r--www/pserv/pkg-descr11
-rw-r--r--www/pserv/pkg-plist4
13 files changed, 972 insertions, 0 deletions
diff --git a/www/pserv/Makefile b/www/pserv/Makefile
new file mode 100644
index 000000000000..728ffd2120db
--- /dev/null
+++ b/www/pserv/Makefile
@@ -0,0 +1,32 @@
+# New ports collection makefile for: pserv
+# Date created: Wed Oct 15 14:16:14 CEST 2003
+# Whom: Alex Dupre <sysadmin@alexdupre.com>
+#
+# $FreeBSD$
+#
+
+PORTNAME= pserv
+PORTVERSION= 3.0.b1
+CATEGORIES= www
+MASTER_SITES= ${MASTER_SITE_SOURCEFORGE}
+MASTER_SITE_SUBDIR= ${PORTNAME}
+DISTNAME= ${PORTNAME}-22-Sep-03
+EXTRACT_SUFX= .tar.Z
+
+MAINTAINER= sysadmin@alexdupre.com
+COMMENT= A portable and small webserver written in C
+
+WRKSRC= ${WRKDIR}/${PORTNAME}
+USE_REINPLACE= yes
+
+post-patch:
+ @${REINPLACE_CMD} "s|%%PREFIX%%|${PREFIX}|g;s|%%LOCALBASE%%|${LOCALBASE}|g" \
+ ${WRKSRC}/pserv.conf
+
+do-install:
+ ${INSTALL_PROGRAM} ${WRKSRC}/pserv ${PREFIX}/sbin/
+ ${INSTALL_DATA} ${WRKSRC}/mime_types.dat ${PREFIX}/etc/mime.types
+ ${INSTALL_DATA} ${WRKSRC}/pserv.conf ${PREFIX}/etc/
+ ${INSTALL_SCRIPT} ${FILESDIR}/pserv.sh ${PREFIX}/etc/rc.d/
+
+.include <bsd.port.mk>
diff --git a/www/pserv/distinfo b/www/pserv/distinfo
new file mode 100644
index 000000000000..6eda3d6fbb2c
--- /dev/null
+++ b/www/pserv/distinfo
@@ -0,0 +1 @@
+MD5 (pserv-22-Sep-03.tar.Z) = 4895631b730836c9202d5ac28b05f0fa
diff --git a/www/pserv/files/patch-Makefile b/www/pserv/files/patch-Makefile
new file mode 100644
index 000000000000..270d791c64a1
--- /dev/null
+++ b/www/pserv/files/patch-Makefile
@@ -0,0 +1,17 @@
+--- Makefile.orig Mon Sep 8 20:05:54 2003
++++ Makefile Thu Oct 16 14:24:50 2003
+@@ -1,11 +1,11 @@
+ #Change the following to your needs
+-CC = gcc
++CC ?= gcc
+ #insert here flags, eg. optimizations
+-CFLAGS = -Wall -O3
+-LIBS = -lnsl -lsocket
+ SRCS = main.c handlers.c mime.c log.c
+ OBJS = main.o handlers.o mime.o log.o
+ PROGRAM = pserv
++
++all : $(PROGRAM)
+
+ $(PROGRAM) : $(OBJS)
+ $(CC) -o $(PROGRAM) $(OBJS) $(LIBS)
diff --git a/www/pserv/files/patch-handlers.c b/www/pserv/files/patch-handlers.c
new file mode 100644
index 000000000000..2a943605a18d
--- /dev/null
+++ b/www/pserv/files/patch-handlers.c
@@ -0,0 +1,362 @@
+--- handlers.c.orig Thu Sep 18 15:26:48 2003
++++ handlers.c Thu Oct 16 14:16:05 2003
+@@ -24,6 +24,7 @@
+ #endif
+
+ extern char cgiRoot[MAX_PATH_LEN+1]; /* root for CGI scripts exec */
++extern char homePath[MAX_PATH_LEN+1]; /* root for PHP scripts exec */
+ extern int port; /* server port */
+ extern char defaultFileName[MAX_PATH_LEN+1]; /* default name for index, default or similar file */
+
+@@ -262,12 +263,33 @@
+ newArgv[i] = NULL; /* we correctly terminate argv */
+
+ i = 0;
++ if (req.contentLength != -1)
++ {
++ sprintf(newEnvp[i++], "CONTENT_LENGTH=%ld", req.contentLength);
++ strcpy(newEnvp[i], "CONTENT_TYPE=");
++ strcat(newEnvp[i++], req.contentType);
++ }
++ strcpy(newEnvp[i], "SERVER_NAME=");
++ strcat(newEnvp[i++], DEFAULT_SERVER_NAME);
+ strcpy(newEnvp[i], "SERVER_SOFTWARE=");
+ strcat(newEnvp[i], SERVER_SOFTWARE_STR);
+ strcat(newEnvp[i], "/");
+ strcat(newEnvp[i++], SERVER_VERSION_STR);
++ strcpy(newEnvp[i], "SERVER_PROTOCOL=");
++ strcat(newEnvp[i++], req.protocolVersion);
+ strcpy(newEnvp[i], "REQUEST_METHOD=");
+ strcat(newEnvp[i++], req.method);
++ strcpy(newEnvp[i], "REMOTE_ADDR=");
++ strcat(newEnvp[i++], req.address);
++ strcpy(newEnvp[i], "HTTP_USER_AGENT=");
++ strcat(newEnvp[i++], req.userAgent);
++ if (req.cookie[0] != '\0')
++ {
++ strcpy(newEnvp[i], "HTTP_COOKIE=");
++ strcat(newEnvp[i++], req.cookie);
++ }
++ strcpy(newEnvp[i], "SCRIPT_FILENAME=");
++ strcat(newEnvp[i++], completedPath);
+ strcpy(newEnvp[i], "SCRIPT_NAME=");
+ strcat(newEnvp[i++], req.documentAddress);
+ strcpy(newEnvp[i], "GATEWAY_INTERFACE=");
+@@ -302,13 +324,256 @@
+ execve(completedPath, newArgv, newEnvp);
+ /* we reach this line only if an execution error occoured */
+ /* logging will happen in the father */
+- printf("\n<HTML><HEAD><TITLE>CGI Error</TITLE></HEAD><BODY><H1>Cgi Exec error</H1></BODY></HTML>\n");
++ printf("\n<HTML><HEAD><TITLE>CGI Error</TITLE></HEAD><BODY><H1>CGI Exec error</H1></BODY></HTML>\n");
+ exit(-1);
+ }
+ return 0;
+ }
+
+-int dumpHeader(sock, filePath, mimeType, req)
++
++#ifdef PHP
++int phpHandler(port, sock, phpFileName, completedPath, req, postStr)
++int port;
++int sock;
++char *phpFileName;
++char *completedPath;
++struct request req;
++char *postStr;
++{
++ char envPath[MAX_PATH_LEN+1]; /* where to hold the envrion PATH parameter */
++ char *relativePath;
++ char scriptWorkingDir[MAX_PATH_LEN+1];
++ char **newArgv;
++ char **newEnvp;
++ int i;
++ int outStdPipe[2]; /* we will redirect the script output to a pipe so we can read it */
++ int inStdPipe[2]; /* we will redirect the script input to a pipe so we can read it */
++ int pid; /* we fork and execute inside the child the script */
++ char pipeReadBuf[PIPE_READ_BUF+1];
++ int howMany;
++ int totalSentFromPipe; /* ampunt of bytes sucked from the pipe and pushed in to the socket */
++ int fatal;
++
++ relativePath = strrchr(completedPath, '/');
++ strncpy(scriptWorkingDir, completedPath, strlen(completedPath) - strlen(relativePath));
++ scriptWorkingDir[strlen(completedPath) - strlen(relativePath)] = '\0';
++
++ /* first we create the pipes needed for stdout redirection */
++ if (pipe(outStdPipe))
++ {
++#ifdef PRINTF_DEBUG
++ printf("Pipe creation error\n");
++ return -1;
++#endif
++ }
++ if (pipe(inStdPipe))
++ {
++#ifdef PRINTF_DEBUG
++ printf("Pipe creation error\n");
++ return -1;
++#endif
++ }
++
++
++ /* now we fork to subsequently execve */
++ pid = fork();
++ if (pid)
++ { /* this is the parent process */
++ if (pid < 0)
++ { /* we check for creation error */
++ printf ("Forking error during cgi exec: %d\n", errno);
++ return -1;
++ }
++ /* we close the unused end of the pipe */
++ close(outStdPipe[WRITE]);
++ close(inStdPipe[READ]);
++
++ if (!strcmp(req.method, "POST")) /* we have to feed the stdin of the script */
++ {
++ if(!strlen(postStr))
++ {
++#ifdef PRINTF_DEBUG
++ printf("cannot post empty data\n");
++#endif
++ return -1;
++ }
++ howMany = write(inStdPipe[WRITE], postStr, strlen(postStr));
++ if (howMany < 0)
++ printf("Error during script pipe read.\n");
++ }
++ totalSentFromPipe = 0;
++ fatal = NO;
++ howMany = 1;
++ while (howMany > 0 && !fatal)
++ {
++ howMany = read(outStdPipe[READ], &pipeReadBuf, PIPE_READ_BUF);
++ if (howMany < 0)
++ printf("Error during script pipe read.\n");
++ else if (!howMany)
++ printf("Nothing read from script pipe.\n");
++ else {
++ pipeReadBuf[howMany] = '\0';
++ if (send(sock, pipeReadBuf, howMany, 0) < 0)
++ {
++ printf("error during CGI sock writing! %d\n", errno);
++ if (errno == EAGAIN)
++ printf("output resource temporarily not available\n");
++ else if (errno == EPIPE)
++ {
++ printf("broken pipe during CGI out.\n");
++ fatal = YES;
++ } else if (errno == EBADF)
++ {
++#ifdef PRINTF_DEBUG
++ printf("invalid out descriptor.\n");
++#endif
++ fatal = YES;
++ }
++ } else
++ totalSentFromPipe += howMany;
++ }
++ }
++ /* now we finished and we clean up */
++ wait(&i);
++ if (i) /* check if execution exited cleanly or with code */
++ logWriter(LOG_CGI_FAILURE, NULL, 0, req, i);
++ else
++ logWriter(LOG_CGI_SUCCESS, NULL, totalSentFromPipe, req, 0);
++ close(outStdPipe[READ]);
++ close(inStdPipe[WRITE]);
++ } else
++ { /* this is the child process */
++ /* now we do some environment setup work */
++ newArgv = calloc(MAX_ARGV_LEN + 1, sizeof(char*));
++ for (i = 0; i < MAX_ARGV_LEN + 1; i++)
++ {
++ newArgv[i] = calloc(MAX_PATH_LEN, sizeof(char));
++ }
++
++ newEnvp = calloc(MAX_ENVP_LEN + 1, sizeof(char*));
++ for (i = 0; i < MAX_ENVP_LEN + 1; i++)
++ {
++ newEnvp[i] = calloc(MAX_PATH_LEN, sizeof(char));
++ }
++
++
++
++ /* extracting PATH env variable */
++ i = 0;
++ while (environ && strncmp(environ[i], PATH_MATCH_STRING, strlen(PATH_MATCH_STRING)))
++ i++;
++ if(environ[i])
++ strcpy(envPath, environ[i]);
++ else
++ envPath[0] = '\0'; /* maybe we should set some default? */
++
++ i = 0;
++ strcpy(newArgv[i++], phpFileName); /* here we should pass the phppath */
++ strcpy(newArgv[i++], completedPath); /* here we should pass the scriptpath */
++ if (strlen(req.queryString))
++ {
++ int toParse;
++ int j, k;
++
++ toParse = YES;
++ j = strlen(req.queryString);
++ while (toParse && j > 0)
++ {
++ if (req.queryString[j] == '=')
++ toParse = NO;
++ j--;
++ }
++ if (toParse)
++ {
++ j = 0;
++ k = 0;
++ howMany = strlen(req.queryString);
++ while (j < howMany)
++ {
++ if (req.queryString[j] == '+')
++ {
++ newArgv[i++][k] = '\0';
++ k = 0;
++ } else
++ newArgv[i][k++] = req.queryString[j];
++ j++;
++ }
++ i++; /* after all we will have at least one argument! */
++ }
++ }
++ newArgv[i] = NULL; /* we correctly terminate argv */
++
++ i = 0;
++ if (req.contentLength != -1)
++ {
++ sprintf(newEnvp[i++], "CONTENT_LENGTH=%ld", req.contentLength);
++ strcpy(newEnvp[i], "CONTENT_TYPE=");
++ strcat(newEnvp[i++], req.contentType);
++ }
++ strcpy(newEnvp[i], "SERVER_NAME=");
++ strcat(newEnvp[i++], DEFAULT_SERVER_NAME);
++ strcpy(newEnvp[i], "SERVER_SOFTWARE=");
++ strcat(newEnvp[i], SERVER_SOFTWARE_STR);
++ strcat(newEnvp[i], "/");
++ strcat(newEnvp[i++], SERVER_VERSION_STR);
++ strcpy(newEnvp[i], "SERVER_PROTOCOL=");
++ strcat(newEnvp[i++], req.protocolVersion);
++ strcpy(newEnvp[i], "REQUEST_METHOD=");
++ strcat(newEnvp[i++], req.method);
++ strcpy(newEnvp[i], "REMOTE_ADDR=");
++ strcat(newEnvp[i++], req.address);
++ strcpy(newEnvp[i], "HTTP_USER_AGENT=");
++ strcat(newEnvp[i++], req.userAgent);
++ if (req.cookie[0] != '\0')
++ {
++ strcpy(newEnvp[i], "HTTP_COOKIE=");
++ strcat(newEnvp[i++], req.cookie);
++ }
++ strcpy(newEnvp[i], "SCRIPT_FILENAME=");
++ strcat(newEnvp[i++], completedPath);
++ strcpy(newEnvp[i], "SCRIPT_NAME=");
++ strcat(newEnvp[i++], req.documentAddress);
++ strcpy(newEnvp[i], "GATEWAY_INTERFACE=");
++ strcat(newEnvp[i++], CGI_VERSION);
++ sprintf(newEnvp[i++], "SERVER_PORT=%d", port);
++ strcpy(newEnvp[i++], envPath);
++ strcpy(newEnvp[i], "QUERY_STRING=");
++ strcat(newEnvp[i++], req.queryString);
++ newEnvp[i] = NULL;
++
++ /* we change the current working directory to the scripts one */
++ if(chdir(scriptWorkingDir))
++ {
++#ifdef PRINTF_DEBUG
++ printf("error while changing PWD in script execution: %d\n", errno);
++#endif
++ }
++
++ close(outStdPipe[READ]); /* we close the unused end*/
++ dup2(outStdPipe[WRITE], 1); /* we duplicate the pipe to the stdout */
++ close(outStdPipe[WRITE]); /* we close the pipe, since we use the duplicate */
++
++ close(inStdPipe[WRITE]); /* we close the unused end*/
++ dup2(inStdPipe[READ], 0); /* we duplicate the pipe to the stdin */
++ close(inStdPipe[READ]); /* we close the pipe, since we use the duplicate */
++
++
++ /* generate a reduced mimeHeader, no type, no size, etc */
++ generateMimeHeader(sock, 200, "", NULL, req.protocolVersion, CGI_ONLY_HEADER);
++
++ /* now we execute the script replacing the current child */
++ execve(phpFileName, newArgv, newEnvp);
++ /* we reach this line only if an execution error occoured */
++ /* logging will happen in the father */
++ printf("\n<HTML><HEAD><TITLE>PHP Error</TITLE></HEAD><BODY><H1>PHP Exec error</H1></BODY></HTML>\n");
++ exit(-1);
++ }
++ return 0;
++}
++#endif
++
++int dumpHeader(port, sock, filePath, mimeType, req)
++int port;
+ int sock;
+ char filePath[];
+ char mimeType[];
+@@ -351,11 +616,11 @@
+ return -1;
+ }
+ stat(filePath, &fileStats);
+- generateMimeHeader(sock, 200, mimeType, &fileStats, req.protocolVersion, FULL_HEADER);
+- logWriter(LOG_GET_SUCCESS, req.documentAddress, (long int)fileStats.st_size, req, 0);
+ howMany = 0;
+ if (strncmp(mimeType, "text", 4)) /* check if it is a text type */
+ { /* raw binary output routine */
++ generateMimeHeader(sock, 200, mimeType, &fileStats, req.protocolVersion, FULL_HEADER);
++ logWriter(LOG_GET_SUCCESS, req.documentAddress, (long int)fileStats.st_size, req, 0);
+ fatal = NO;
+ retry = NO;
+ while(!feof(inFile) && !fatal)
+@@ -399,11 +664,11 @@
+ if (howMany > 0)
+ {
+ #ifdef ON_THE_FLY_CONVERSION
+- {
+- int i;
+- for (i = 0; i < howMany; i++)
+- if(outBuff[i] == '\r') outBuff[i] = '\n';
+- }
++ {
++ int i;
++ for (i = 0; i < howMany; i++)
++ if(outBuff[i] == '\r') outBuff[i] = '\n';
++ }
+ #endif
+ if (send(sock, outBuff, howMany, 0) < 0)
+ {
+@@ -449,7 +714,7 @@
+ FILE *tempFile;
+ size_t generatedBytes;
+ char tempStr[MAX_PATH_LEN+1];
+- char linkStr[MAX_PATH_LEN+1];
++ char linkStr[MAX_PATH_LEN+2];
+ time_t currTime;
+ char timeStr[256];
+
+@@ -497,10 +762,16 @@
+ if (strcmp(dp->d_name, ".")) /* not self */
+ {
+ if (strcmp(dp->d_name, ".."))
++ {
+ strcpy(linkStr, dp->d_name);
+- else
++ if (dp->d_type == DT_DIR)
++ strcat(linkStr, "/");
++ sprintf(tempStr, "<A HREF=\"%s\">%s</A><BR>\n", linkStr, linkStr);
++ } else
++ {
+ strcpy(linkStr, "Parent Directory");
+- sprintf(tempStr, "<A HREF=\"%s\">%s</A><BR>\n", dp->d_name, linkStr);
++ sprintf(tempStr, "<A HREF=\"%s/\">%s</A><BR>\n", dp->d_name, linkStr);
++ }
+ generatedBytes += strlen(tempStr);
+ fprintf(tempFile, "%s\n", tempStr);
+ }
diff --git a/www/pserv/files/patch-handlers.h b/www/pserv/files/patch-handlers.h
new file mode 100644
index 000000000000..939a714d8dca
--- /dev/null
+++ b/www/pserv/files/patch-handlers.h
@@ -0,0 +1,10 @@
+--- handlers.h.orig Wed Oct 15 17:06:59 2003
++++ handlers.h Wed Oct 15 17:07:08 2003
+@@ -19,6 +19,7 @@
+
+ /* handlers.c */
+ int cgiHandler();
++int phpHandler();
+ int dumpHeader();
+ int dumpFile();
+ int generateIndex();
diff --git a/www/pserv/files/patch-main.c b/www/pserv/files/patch-main.c
new file mode 100644
index 000000000000..e9ae61cbe1b6
--- /dev/null
+++ b/www/pserv/files/patch-main.c
@@ -0,0 +1,386 @@
+--- main.c.orig Mon Sep 22 10:39:24 2003
++++ main.c Thu Oct 16 14:00:02 2003
+@@ -23,6 +23,7 @@
+ char defaultFileName[MAX_PATH_LEN+1];
+ char logFileName[MAX_PATH_LEN+1];
+ char mimeTypesFileName[MAX_PATH_LEN+1];
++char phpFileName[MAX_PATH_LEN+1];
+ char cgiRoot[MAX_PATH_LEN+1]; /* root for CGI scripts exec */
+ struct timeval sockTimeVal;
+ mimeData *mimeArray; /* here we will hold all MIME data, inited once, never to be changed */
+@@ -206,10 +207,10 @@
+ int reqSize;
+ int readLines;
+ int tokenEnd;
+-
+- /* we copy the header lines to an array for easier parsing */
++
++ /* we copy the header lines to an array for easier parsing */
+ /* but first we make sure that our string has a newline and an end */
+- req[BUFFER_SIZE] = '\0';
++ req[BUFFER_SIZE] = '\0';
+ reqSize = strlen(req);
+ req[reqSize] = '\n';
+ reqSize++;
+@@ -230,7 +231,7 @@
+ for (k = 0; k < readLines; k++)
+ printf("%d - |%s|\n", k, reqArray[k]);
+ #endif
+-
++
+ /* first line: method, path and protocol version */
+ /* we copy to a temporary buffer to be more secure against overflows */
+ i = j = 0;
+@@ -246,7 +247,7 @@
+ else
+ tokenEnd = NO;
+ i++;
+-
++
+ /* we look for the document address */
+ j = 0;
+ reqStruct->documentAddress[0] = '\0';
+@@ -259,14 +260,14 @@
+ else
+ token[j] = '\0'; /* to make sure we have a string */
+ /* now we need to convert some escapings from the path like %20 */
+- convertPercents(token, j);
++ convertPercents(token, j);
+ strcpy(reqStruct->documentAddress, token); /* copy back */
+ if (reqArray[0][i] == '\0')
+ tokenEnd = YES;
+ else
+ tokenEnd = NO;
+ i++;
+-
++
+ /* we need now to separate path from query string ("?" separated) */
+ if (reqArray[0][i-1] == '?')
+ {
+@@ -282,7 +283,7 @@
+ i++;
+ }
+ }
+-
++
+ /* we analyze the HTTP protocol version */
+ /* default is 0.9 since that version didn't report itself */
+ strcpy(reqStruct->protocolVersion, "HTTP/0.9");
+@@ -306,10 +307,13 @@
+ else if (!strncmp(reqArray[1], "Connection: Keep-Alive", strlen("Connection: keep-alive")))
+ reqStruct->keepAlive = YES;
+
+- /* user-agent, content-length and else */
++ /* user-agent, content-length, content-type, cookie and else */
+ i = 1;
+ j = NO;
+ reqStruct->userAgent[0] = '\0';
++ reqStruct->contentLength = -1;
++ reqStruct->contentType[0] = '\0';
++ reqStruct->cookie[0] = '\0';
+ while (i < readLines)
+ {
+ if (!strncmp(reqArray[i], "User-Agent:", strlen("User-Agent:")))
+@@ -317,14 +321,28 @@
+ strncpy(reqStruct->userAgent, &reqArray[i][strlen("User-Agent: ")], USER_AGENT_LEN - 1);
+ reqStruct->userAgent[USER_AGENT_LEN] = '\0';
+ }
+- else if (!strncmp(reqArray[i], "Content-Length:", strlen("Content-length:")) || !strncmp(reqArray[i], "Content-length:", strlen("Content-length:")))
+- {
+- strcpy(token, &reqArray[i][strlen("Content-length: ")]);
+- sscanf(token, "%ld", &(reqStruct->contentLength));
++ else if (!strncmp(reqArray[i], "Content-Length:", strlen("Content-length:")) || !strncmp(reqArray[i], "Content-length:", strlen("Content-length:")))
++ {
++ strcpy(token, &reqArray[i][strlen("Content-length: ")]);
++ sscanf(token, "%ld", &(reqStruct->contentLength));
+ #ifdef PRINTF_DEBUG
+- printf("content length %ld\n", reqStruct->contentLength);
++ printf("content length %ld\n", reqStruct->contentLength);
+ #endif
+- }
++ }
++ else if (!strncmp(reqArray[i], "Content-Type:", strlen("Content-type:")) || !strncmp(reqArray[i], "Content-type:", strlen("Content-type:")))
++ {
++ strncpy(reqStruct->contentType, &reqArray[i][strlen("Content-type: ")], CONTENT_TYPE_LEN - 1);
++#ifdef PRINTF_DEBUG
++ printf("content type %s\n", reqStruct->contentType);
++#endif
++ }
++ else if (!strncmp(reqArray[i], "Cookie:", strlen("Cookie:")))
++ {
++ strncpy(reqStruct->cookie, &reqArray[i][strlen("Cookie: ")], MAX_COOKIE_LEN - 1);
++#ifdef PRINTF_DEBUG
++ printf("cookie %s\n", reqStruct->cookie);
++#endif
++ }
+ i++;
+ }
+ /* if we didn't find a User-Aget we fill in a (N)ot(R)ecognized */
+@@ -414,18 +432,39 @@
+ /* we append the default file name */
+ strcat(completeFilePath, defaultFileName);
+ analyzeExtension(mimeType, completeFilePath);
+- dumpFile(sock, completeFilePath, mimeType, req);
++#ifdef PHP
++ if (strncmp(mimeType, "application/x-httpd-php", 23))
++#endif
++ dumpFile(sock, completeFilePath, mimeType, req);
++#ifdef PHP
++ else
++ phpHandler(port, sock, phpFileName, completeFilePath, req, NULL);
++#endif
+ }
+ #else
+ /* we append the default file name */
+ strcat(completeFilePath, defaultFileName);
+ analyzeExtension(mimeType, completeFilePath);
+- dumpFile(sock, completeFilePath, mimeType, req);
++#ifdef PHP
++ if (strncmp(mimeType, "application/x-httpd-php", 23))
++#endif
++ dumpFile(sock, completeFilePath, mimeType, req);
++#ifdef PHP
++ else
++ phpHandler(port, sock, phpFileName, completeFilePath, req, NULL);
++#endif
+ #endif
+ } else
+ { /* it is a plain file */
+ analyzeExtension(mimeType, completeFilePath);
+- dumpFile(sock, completeFilePath, mimeType, req);
++#ifdef PHP
++ if (strncmp(mimeType, "application/x-httpd-php", 23))
++#endif
++ dumpFile(sock, completeFilePath, mimeType, req);
++#ifdef PHP
++ else
++ phpHandler(port, sock, phpFileName, completeFilePath, req, NULL);
++#endif
+ }
+ }
+ } else if (!strcmp(req.method, "HEAD"))
+@@ -494,7 +533,14 @@
+ strcat(completeFilePath, defaultFileName);
+ }
+ analyzeExtension(mimeType, completeFilePath);
+- dumpHeader(sock, completeFilePath, mimeType, req);
++#ifdef PHP
++ if (strncmp(mimeType, "application/x-httpd-php", 23))
++#endif
++ dumpFile(sock, completeFilePath, mimeType, req);
++#ifdef PHP
++ else
++ phpHandler(port, sock, phpFileName, completeFilePath, req, NULL);
++#endif
+ }
+ } else if (!strcmp(req.method, "POST"))
+ {
+@@ -507,13 +553,6 @@
+ int readFinished;
+
+ printf("Handling of POST method\n");
+- /* first we check if the path contains the directory selected for cgi's and in case handle it */
+- if (strncmp(req.documentAddress, CGI_MATCH_STRING, strlen(CGI_MATCH_STRING)))
+- {
+- /* non cgi POST is not supported */
+- sayError(sock, UNHANDLED_METHOD, "", req);
+- return -1;
+- }
+ #ifdef PRINTF_DEBUG
+ printf ("begin of post handling\n");
+
+@@ -523,9 +562,15 @@
+ totalRead = 0;
+ stuckCounter = 0;
+ timeOutCounter = 0;
+- while (!readFinished)
+- {
+- howMany = recv(newSocket, tempBuff, BUFFER_SIZE, 0);
++
++ /* SECURITY: Avoid malicious Content-Length -- check \r\n\r\n\0 also */
++ if (req.contentLength < 0 || req.contentLength >= BUFFER_SIZE-5) {
++ sayError(sock, 500, "", req);
++ return -1;
++ }
++
++ /* SECURITY: Remove loop to prevent buffer overflow */
++ howMany = recv(newSocket, tempBuff, req.contentLength+5, 0);
+ tempBuff[howMany] = '\0'; /* seems that some Unices need this */
+ #ifdef PRINTF_DEBUG
+ printf ("read: %d\n%s\n", howMany, tempBuff);
+@@ -579,16 +624,15 @@
+ if (howMany == req.contentLength)
+ readFinished = YES;
+ }
+- }
+ #ifdef PRINTF_DEBUG
+- printf("total read %d\n", totalRead);
++ printf("total read %d\n", totalRead);
+ #endif
+- if (totalRead == 0)
+- {
+- printf("Request read error\n");
+- } else
+- {
+- if (buff[totalRead - 1] != '\n') /* we need a trailing \n or the script will wait forever */
++ if (totalRead == 0)
++ {
++ printf("Request read error\n");
++ } else
++ {
++ if (buff[totalRead - 1] != '\n') /* we need a trailing \n or the script will wait forever */
+ {
+ buff[totalRead++] = '\n';
+ buff[totalRead] = '\0';
+@@ -596,7 +640,77 @@
+ #ifdef PRINTF_DEBUG
+ printf("buff: |%s|\n", buff);
+ #endif
+- cgiHandler(port, sock, req, buff);
++ if (!strncmp(req.documentAddress, CGI_MATCH_STRING, strlen(CGI_MATCH_STRING)))
++ {
++ cgiHandler(port, sock, req, buff);
++ } else
++ {
++#ifdef PHP
++ strcpy(completeFilePath, homePath);
++ strcat(completeFilePath, req.documentAddress);
++ /* now we check if the given path tries to get out of the root */
++ {
++ int i,j;
++ int sL;
++ char dirName[MAX_PATH_LEN+1];
++ int depthCount = 0;
++
++ sL = strlen(req.documentAddress);
++ dirName[0] = '\0';
++ if (sL > 3) {
++ dirName[0] = req.documentAddress[1];
++ dirName[1] = req.documentAddress[2];
++ dirName[2] = req.documentAddress[3];
++ dirName[3] ='\0';
++ if (!strcmp(dirName, "../"))
++ {
++ sayError(sock, FORBIDDEN, req.documentAddress, req);
++ return -1;
++ }
++ }
++ j = 0;
++ for (i = 1; i < sL; i++) {
++ if (req.documentAddress[i] == '/')
++ {
++ dirName[j] = '\0';
++ if (strcmp(dirName, ".."))
++ depthCount ++;
++ else
++ depthCount--;
++ j = 0;
++ } else
++ dirName[j++] = req.documentAddress[i];
++ }
++ if (depthCount < 0)
++ {
++ sayError(sock, FORBIDDEN, req.documentAddress, req);
++ return -1;
++ }
++ }
++ /* now we check if the given file is a directory or a plain file */
++ stat(completeFilePath, &fileStats);
++ if ((fileStats.st_mode & S_IFDIR) == S_IFDIR)
++ {
++ /* if does not end with a slash, we get an error */
++ if(completeFilePath[strlen(completeFilePath)-1] != '/')
++ {
++ sayError(sock, NOT_FOUND, req.documentAddress, req);
++ return -1;
++ }
++ /* we append the default file name */
++ strcat(completeFilePath, defaultFileName);
++ }
++ analyzeExtension(mimeType, completeFilePath);
++ if (strncmp(mimeType, "application/x-httpd-php", 23))
++ {
++#endif
++ /* non cgi POST is not supported */
++ sayError(sock, UNHANDLED_METHOD, "", req);
++ return -1;
++#ifdef PHP
++ } else phpHandler(port, sock, phpFileName, completeFilePath, req, buff);
++#endif
++ }
+ }
+ } else
+ {
+@@ -625,7 +739,7 @@
+ f = fopen(configFile, "r");
+ if (f == NULL)
+ {
+- printf("Error opening config file. Setting defaults.\n");
++ printf("Config file not found. Setting defaults.\n");
+ *serverPort = DEFAULT_PORT;
+ *maxChildren = DEFAULT_MAX_CHILDREN;
+ strcpy(homePath, DEFAULT_DOCS_LOCATION);
+@@ -634,7 +748,9 @@
+ sockTimeVal.tv_usec = DEFAULT_USEC_TO;
+ strcpy(logFileName, DEFAULT_LOG_FILE);
+ strcpy(mimeTypesFileName, DEFAULT_MIME_FILE);
++ strcpy(phpFileName, DEFAULT_PHP_FILE);
+ strcpy(cgiRoot, DEFAULT_CGI_ROOT);
++ initMimeTypes();
+ return -1;
+ }
+ if (!feof(f)) fscanf(f, "%s %s", str1, str2);
+@@ -735,11 +851,25 @@
+ if (mimeTypesFileName == NULL)
+ {
+ strcpy(mimeTypesFileName, DEFAULT_MIME_FILE);
+- printf("Error reading mimeTypesFileName from file, setting default, %s\n", mimeTypesFileName);
++ printf("Error reading mimeTypesFile from file, setting default, %s\n", mimeTypesFileName);
+ }
+ } else {
+ strcpy(mimeTypesFileName, DEFAULT_MIME_FILE);
+- printf("Error reading mimeTypesFileName from file, setting default, %s\n", mimeTypesFileName);
++ printf("Error reading mimeTypesFile from file, setting default, %s\n", mimeTypesFileName);
++ }
++ if (!feof(f)) fscanf(f, "%s %s", str1, str2);
++ if (str1 != NULL && str2 != NULL && !strcmp(str1, "phpFile"))
++ {
++ sscanf(str2, "%s", phpFileName);
++ if (logFileName == NULL)
++ {
++ strcpy(phpFileName, DEFAULT_LOG_FILE);
++ printf("Error reading phpFile from file, setting default, %s\n", phpFileName);
++ }
++ } else
++ {
++ strcpy(phpFileName, DEFAULT_PHP_FILE);
++ printf("Error reading phpFile from file, setting default, %s\n", phpFileName);
+ }
+ if (!feof(f)) fscanf(f, "%s %s", str1, str2);
+ if (str1 != NULL && str2 != NULL && !strcmp(str1, "cgiRoot"))
+@@ -775,6 +905,7 @@
+ int readFinished;
+ struct request gottenReq;
+ int isKeepAlive;
++ int bool;
+ struct sockaddr_in listenName; /* data struct for the listen port */
+ struct sockaddr_in acceptedSockStruct; /* sockaddr for the internetworking */
+ int acceptedSocketLen; /* size of the structure */
+@@ -808,9 +939,16 @@
+ printf("socket creation error occoured\n");
+ return -1;
+ }
++ bool = 1;
++ error = setsockopt (theSocket, SOL_SOCKET, SO_REUSEADDR, &bool, sizeof(bool));
++ if (error == -1)
++ { if (errno == EADDRINUSE)
++ printf("set socket option error occoured\n");
++ return -1;
++ }
+ error = bind (theSocket, (struct sockaddr*) &listenName, sizeof(listenName));
+ if (error == -1)
+- {
++ { if (errno == EADDRINUSE)
+ printf("socket binding error occoured\n");
+ return -2;
+ }
diff --git a/www/pserv/files/patch-main.h b/www/pserv/files/patch-main.h
new file mode 100644
index 000000000000..4419788ac639
--- /dev/null
+++ b/www/pserv/files/patch-main.h
@@ -0,0 +1,65 @@
+--- main.h.orig Fri Sep 19 00:36:03 2003
++++ main.h Thu Oct 16 13:52:18 2003
+@@ -24,11 +24,12 @@
+
+
+ /* --- CPP parsing options --- */
+-#define PRINTF_DEBUG /* enable this to print some debugging messages */
++#undef PRINTF_DEBUG /* enable this to print some debugging messages */
+ #undef ON_THE_FLY_CONVERSION /* enable this for line ending conversion */
+ #undef BRAIN_DEAD_CAST /* if your compiler is brainwashed and does not cast standard types.h structures */
+ #define FORKING_SERVER /* enables to fork for every request */
+ #define AUTO_INDEX /* enables auto-index of directories */
++#define PHP /* enables transparent PHP support */
+
+ /* --- Configure options --- */
+ #define CONFIG_FILE_NAME "pserv.conf"
+@@ -39,19 +40,19 @@
+ #define MIME_TYPE_DEFAULT "application/octet-stream"
+
+ /* configuration file location */
+-#define DEFAULT_CONFIG_LOCATION "/export/home/multix/pserv/"
+-//#define DEFAULT_CONFIG_LOCATION "/Users/multix/Documents/code/pserv/"
++#define DEFAULT_CONFIG_LOCATION "/usr/local/etc/"
+
+ /* hard-wired defaults, if loading of config file fails */
+-#define DEFAULT_PORT 2000
++#define DEFAULT_PORT 80
+ #define DEFAULT_MAX_CHILDREN 5
+-#define DEFAULT_DOCS_LOCATION "/export/home/multix/public_html"
++#define DEFAULT_DOCS_LOCATION "/usr/local/www/data"
+ #define DEFAULT_FILE_NAME "index.html"
+ #define DEFAULT_SEC_TO 1
+ #define DEFAULT_USEC_TO 100
+-#define DEFAULT_LOG_FILE "/export/home/multix/pserv/pserv.log"
+-#define DEFAULT_MIME_FILE "/export/home/multix/pserv/mime_types.dat"
+-#define DEFAULT_CGI_ROOT "/export/home/multix/public_html/cgi-bin"
++#define DEFAULT_LOG_FILE "/var/log/pserv.log"
++#define DEFAULT_MIME_FILE "/usr/local/etc/mime.types"
++#define DEFAULT_PHP_FILE "/usr/local/bin/php"
++#define DEFAULT_CGI_ROOT "/usr/local/www/cgi-bin"
+ #define DEFAULT_SERVER_NAME "localhost"
+
+ /* amount of connections queued in listening */
+@@ -120,9 +121,11 @@
+ #define ADDRESS_LEN 16
+ #define METHOD_LEN 16
+ #define PROTOCOL_LEN 16
++#define CONTENT_TYPE_LEN 256
+ #define USER_AGENT_LEN 256
+ #define MAX_QUERY_STRING_LEN 1024
+ #define MAX_PATH_LEN 1024
++#define MAX_COOKIE_LEN 4096
+
+ struct request
+ {
+@@ -133,7 +136,9 @@
+ char protocolVersion[PROTOCOL_LEN+1];
+ int keepAlive;
+ char userAgent[USER_AGENT_LEN+1];
++ char cookie[MAX_COOKIE_LEN+1];
+ long int contentLength;
++ char contentType[CONTENT_TYPE_LEN+1];
+ char rest[BUFFER_SIZE+1];
+ };
+
diff --git a/www/pserv/files/patch-mime.c b/www/pserv/files/patch-mime.c
new file mode 100644
index 000000000000..8d4c7252c024
--- /dev/null
+++ b/www/pserv/files/patch-mime.c
@@ -0,0 +1,34 @@
+--- mime.c.orig Thu Sep 18 15:26:55 2003
++++ mime.c Wed Oct 15 18:38:42 2003
+@@ -43,8 +43,8 @@
+ f = fopen(mimeTypesFileName, "r");
+ if (f == NULL)
+ {
+- printf("Error opening mime types file. Setting defaults.\n");
+- entries = 3;
++ printf("Mime types file not found. Setting defaults.\n");
++ entries = 6;
+ mimeArray = (mimeData *) calloc(entries, sizeof(mimeData));
+ if (mimeArray == NULL) {
+ printf("Errory while allocating mime types Array. Exiting.\n");
+@@ -52,10 +52,16 @@
+ }
+ strcpy(mimeArray[0].ext, "html");
+ strcpy(mimeArray[0].type, "text/html");
+- strcpy(mimeArray[1].ext, "gif");
+- strcpy(mimeArray[1].type, "image/gif");
+- strcpy(mimeArray[2].ext, "jpg");
+- strcpy(mimeArray[2].type, "image/jpg");
++ strcpy(mimeArray[1].ext, "htm");
++ strcpy(mimeArray[1].type, "text/html");
++ strcpy(mimeArray[2].ext, "gif");
++ strcpy(mimeArray[2].type, "image/gif");
++ strcpy(mimeArray[3].ext, "jpg");
++ strcpy(mimeArray[3].type, "image/jpg");
++ strcpy(mimeArray[4].ext, "png");
++ strcpy(mimeArray[4].type, "image/png");
++ strcpy(mimeArray[5].ext, "php");
++ strcpy(mimeArray[5].type, "application/x-httpd-php");
+ mimeEntries = entries;
+ return -1;
+ }
diff --git a/www/pserv/files/patch-mime_types.dat b/www/pserv/files/patch-mime_types.dat
new file mode 100644
index 000000000000..e2378527f61f
--- /dev/null
+++ b/www/pserv/files/patch-mime_types.dat
@@ -0,0 +1,7 @@
+--- mime_types.dat.orig Wed Oct 15 15:57:08 2003
++++ mime_types.dat Wed Oct 15 15:57:22 2003
+@@ -14,3 +14,4 @@
+ tar application/x-tar
+ lha application/octet-stream
+ lzh application/octet-stream
++php application/x-httpd-php
diff --git a/www/pserv/files/patch-pserv.conf b/www/pserv/files/patch-pserv.conf
new file mode 100644
index 000000000000..1580f655cd41
--- /dev/null
+++ b/www/pserv/files/patch-pserv.conf
@@ -0,0 +1,18 @@
+--- pserv.conf.orig Wed Oct 15 16:18:05 2003
++++ pserv.conf Wed Oct 15 16:20:01 2003
+@@ -1,9 +1,10 @@
+-port 80
++port 80
+ maxChildren 4
+-documentsPath /export/home/multix/public_html
++documentsPath %%PREFIX%%/www/data
+ defaultFile index.html
+ secTimeout 1
+ uSecTimeout 100000
+-logFile /export/home/multix/pserv/pserv.log
+-mimeTypesFile /export/home/multix/pserv/mime_types.dat
+-cgiRoot /export/home/multix/public_html/cgi-bin
++logFile /var/log/pserv.log
++mimeTypesFile %%PREFIX%%/etc/mime.types
++phpFile %%LOCALBASE%%/bin/php
++cgiRoot %%PREFIX%%/www/cgi-bin
diff --git a/www/pserv/files/pserv.sh b/www/pserv/files/pserv.sh
new file mode 100644
index 000000000000..9930e58c7886
--- /dev/null
+++ b/www/pserv/files/pserv.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+if ! PREFIX=$(expr $0 : "\(/.*\)/etc/rc\.d/${0##*/}\$"); then
+ echo "$0: Cannot determine the PREFIX" >&2
+ exit 64
+fi
+
+case "$1" in
+start)
+ if [ -x ${PREFIX}/sbin/pserv ]; then
+ ${PREFIX}/sbin/pserv > /dev/null &
+ echo -n ' pserv'
+ fi
+ ;;
+stop)
+ killall pserv > /dev/null 2>&1
+ echo -n ' pserv'
+ ;;
+*)
+ echo "Usage: `basename $0` {start|stop}" >&2
+ exit 64
+ ;;
+esac
+
+exit 0
diff --git a/www/pserv/pkg-descr b/www/pserv/pkg-descr
new file mode 100644
index 000000000000..066df7a9ccc6
--- /dev/null
+++ b/www/pserv/pkg-descr
@@ -0,0 +1,11 @@
+pServ is a small, portable HTTP server. It is written in pure C for speed and
+portability. It runs as a standalone program and does not require inetd.
+It should be small enough to be used in a mobile computer or to be run on your
+obsolete workstation you have somewhere.
+
+This port contains a patched version to support the execution of php scripts.
+
+WWW: http://sourceforge.net/projects/pserv/
+
+- Alex Dupre
+sysadmin@alexdupre.com
diff --git a/www/pserv/pkg-plist b/www/pserv/pkg-plist
new file mode 100644
index 000000000000..930e95b16861
--- /dev/null
+++ b/www/pserv/pkg-plist
@@ -0,0 +1,4 @@
+sbin/pserv
+etc/mime.types
+etc/pserv.conf
+etc/rc.d/pserv.sh