Article 12674 of alt.sources:
Path: nntpd.lkg.dec.com!crl.dec.com!crl.dec.com!caen!zip.eecs.umich.edu!panix!news.mathworks.com!europa.chnt.gtegsc.com!howland.reston.ans.net!cs.utexas.edu!venus.sun.com!nntp-hub2.barrnet.net!news1.digital.com!vixie!gw.home.vix.com!vixie
From: paul@vix.com (Paul A Vixie)
Newsgroups: alt.sources
Subject: Thierry Leconte: homehttp : A very simple http server
Date: 28 Jul 1995 00:22:41 -0700
Organization: Vixie Enterprises
Lines: 288
Sender: vixie@vix.com
Message-ID: <9507280722.AA03516@gw.home.vix.com>
NNTP-Posting-Host: gw.home.vix.com
X-Received: by gw.home.vix.com id AA03516; Fri, 28 Jul 95 00:22:39 -0700
X-To: alt.sources.usenet
X-Reply-To: leconte@irisa.fr

this was sent to comp.sources.unix, but as it is lacking a man page and
readme file i have rejected it.  i'm posting it here since it seems like
a useful program and i'm sure the author would like everyone to see it.

--mod

------- Forwarded Message

Replied: Fri, 28 Jul 1995 00:20:58 -0700
Replied: "leconte@irisa.fr "
Delivery-Date: Thu, 27 Jul 1995 08:45:38 -0700
Return-Path: news@news.irisa.fr
Received: by gw.home.vix.com id AA06135; Thu, 27 Jul 95 08:45:33 -0700
Received: from news.irisa.fr (news.irisa.fr [131.254.254.15]) by grasp.insa-lyon.fr (8.7.Beta.4/8.7.Beta.3) with SMTP id RAA17786 for <comp-sources-unix@moderators.univ-lyon1.fr>; Thu, 27 Jul 1995 17:45:22 +0200
Received: (from news@localhost) by news.irisa.fr (8.6.10/8.6.9) id RAA29474; Thu, 27 Jul 1995 17:45:18 +0200
To: comp-sources-unix@moderators.univ-lyon1.fr
Path: usenet
From: leconte@irisa.fr (Thierry Leconte)
Newsgroups: comp.sources.unix
Subject: homehttp : A very simple http server
Date: 27 Jul 1995 15:45:17 GMT
Organization: Irisa, Rennes (FR)
Lines: 256
Distribution: world
Message-Id: <3v8cad$smq@news.irisa.fr>
Reply-To: leconte@irisa.fr
Nntp-Posting-Host: spam.irisa.fr


Here the source of a very little and very simple http server.
I write it just for the fun but could help people who want to
run a server just for a home page.
It answers only to GET requests and serve only file with o+r rights
and without .. in the path.

By default it serves files in HOME dir but the -d option can change that.
Use  -l if you want a log of incomming requests.
- -p is useful to change the listening port number (Don't forget to give a good
URL like http://machine:portnumber/file if you change the default value 80).

It works on Sun but must be easly portable on other platforms.

Here it is 
- ----------------------------CUT HERE-----------------------------------
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>

/* Copyright (C) 1995, Thierry Leconte. All Rights Reserved. */

/*
 * Disclaimer of Warranty
 * 
 * These software programs are available to the user without any license fee or
 * royalty on an "as is" basis.  Thierry Leconte disclaims any and all
 * warranties, whether express, implied, or statuary, including any implied
 * warranties or merchantability or of fitness for a particular purpose.  In
 * no event shall the copyright-holder be liable for any incidental,
 * punitive, or consequential damages of any kind whatsoever arising from the
 * use of these programs.
 * 
 */

int             http_sock, con_sock;
int             http_port = 80;
struct sockaddr_in source;
char           *log_httpfile = NULL;
char           *homedir;
int             uid;

void 
fermesock(int n)
{
	close(con_sock);
	close(http_sock);

	log_http("SIGTERM", "");
	exit(0);
}

void
init_servconnection(void)
{
	struct sockaddr_in server;

	/* Creation socket */
	http_sock = socket(AF_INET, SOCK_STREAM, 0);
	if (http_sock < 0) {
		perror("socket");
		exit(1);
	}
	signal(SIGTERM, fermesock);
	server.sin_family = AF_INET;
	server.sin_port = http_port;
	server.sin_addr.s_addr = INADDR_ANY;
	if (bind(http_sock, (struct sockaddr *) & server, sizeof(server)) < 0) {
		perror("bind socket");
		exit(1);
	}
	if (listen(http_sock, 1) < 0) {
		perror("listen");
		exit(-1);
	}
}

void
attenteconnection(void)
{
	int             lg;

	lg = sizeof(struct sockaddr_in);
	con_sock = accept(http_sock, (struct sockaddr *) & source, &lg);
	if (con_sock <= 0) {
		perror("accept");
		exit(-1);
	}
}

usage()
{
	fprintf(stderr, "usage homehttpd [-l log_httpfile][-p port][-d homedir][-u uid]\n");
	exit(-1);
}

char            rep_err_nget[] = "<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY><H1>Error 405</H1>\
This server answer only to GET requests\n</BODY></HTML>\n";
char            rep_err_acc[] = "<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY><H1>Error 404</H1>\
Not found - file doesn't exist or is read protected\n</BODY></HTML>\n";

log_http(char *action, char *item)
{
	int             fd;
	char            logline[1024];
	time_t          tl;

	if (log_httpfile == NULL)
		return;

	tl = time(NULL);
	strcpy(logline, ctime(&tl));
	logline[strlen(logline) - 1] = ' ';
	strcat(logline, inet_ntoa(source.sin_addr));
	strcat(logline, " ");
	strcat(logline, action);
	strcat(logline, ":");
	strcat(logline, item);
	strcat(logline, "\n");


	fd = open(log_httpfile, O_WRONLY | O_APPEND | O_CREAT, 0600);
	if (fd < 0) {
		perror("open log file");
		exit(-1);
	}
	write(fd, logline, strlen(logline));
	close(fd);
}

traite_req(char *req)
{
	char            buff[1024];
	int             fd, lg;
	char           *filename, *c;
	struct stat     statres;

	if (strcmp(strtok(req, " "), "GET") != 0) {
		write(con_sock, rep_err_nget, strlen(rep_err_nget));
		log_http("error 405", req);
		return;
	}
	filename = strtok(NULL, " ");
	/* saute le / */
	filename++;

	/* interdit les .. dans le path */
	c = filename;
	while (*c != '\0')
		if (c[0] == '.' && c[1] == '.') {
			write(con_sock, rep_err_acc, strlen(rep_err_acc));
			log_http("error 404", filename);
			return;
		} else
			c++;

	fd = open(filename, O_RDONLY);
	if (fd < 0) {
		write(con_sock, rep_err_acc, strlen(rep_err_acc));
		log_http("error 404", filename);
		return;
	}
	if (fstat(fd, &statres) < 0) {
		write(con_sock, rep_err_acc, strlen(rep_err_acc));
		log_http("error 404", filename);
		close(fd);
		return;
	}
	if (statres.st_uid != uid ||
	    !S_ISREG(statres.st_mode) ||
	    !(statres.st_mode & S_IROTH)) {
		write(con_sock, rep_err_acc, strlen(rep_err_acc));
		log_http("error 404", filename);
		close(fd);
		return;
	}
	while (lg = read(fd, buff, 1024))
		write(con_sock, buff, lg);
	close(fd);

	log_http("GET", filename);
}

main(int argc, char **argv)
{
	char            requete[1024];
	int             lg;

	uid = getuid();

	argc--;
	argv++;
	while (argc > 0) {
		if (argv[0][0] != '-')
			usage();
		switch (argv[0][1]) {
		case 'l':
			log_httpfile = argv[1];
			argv += 2;
			argc -= 2;
			break;
		case 'p':
			http_port = atoi(argv[1]);
			argv += 2;
			argc -= 2;
			break;
		case 'u':
			uid = atoi(argv[1]);
			argv += 2;
			argc -= 2;
			break;
		case 'd':
			homedir = argv[1];
			argv += 2;
			argc -= 2;
			break;
		default:
			usage();
		}
	}

	if (homedir == NULL)
		homedir = getenv("HOME");

	if (chdir(homedir) < 0) {
		perror("chdir");
		exit(-1);
	}
	init_servconnection();

	do {
		attenteconnection();

		lg = read(con_sock, requete, 1024);

		traite_req(requete);

		close(con_sock);
	} while (1);

}








------- End of Forwarded Message



