Simple_HTTPd on steroids - major rework of the original program, by
William Lloyd. New features include: * many additional command line options * "fetch" mode * less bugs :-) * better README. Submitted by: William Lloyd <wlloyd@lap.net> Reviewed by: abial
This commit is contained in:
parent
0a863b6b19
commit
44741b5aa7
@ -1,10 +1,7 @@
|
||||
# $Id: Makefile,v 1.2.2.1 1999/02/05 12:21:41 abial Exp $
|
||||
# $Id: Makefile,v 1.3 1999/02/12 20:36:13 abial Exp $
|
||||
#
|
||||
PROG=simple_httpd
|
||||
SRCS= simple_httpd.c
|
||||
CFLAGS+=-g
|
||||
NOMAN=yes
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
||||
|
||||
|
@ -1,23 +1,167 @@
|
||||
This is a small HTTP server. This version is under BSD license.
|
||||
It's very simple, yet sufficient for serving basic Web contents,
|
||||
including ability to run CGI scripts.
|
||||
Simple_httpd - A small and free Web server
|
||||
|
||||
"Simple_httpd is like /usr/bin/mail is to mail clients, no frills."
|
||||
|
||||
This HTTP server can be used in any FreeBSD/PicoBSD application.
|
||||
|
||||
It has been tested under FreeBSD 2.2.x, 3.x and 4.x. It might work
|
||||
on other OS systems, but it's for FreeBSD primarily.
|
||||
|
||||
The main advantage to Simple_httpd is that it is very small.
|
||||
The 25K binary can satisfy most needs in a small or embedded
|
||||
appplication. If you want a full featured server see
|
||||
/usr/ports/www/apache* or http://www.apache.org
|
||||
|
||||
Simple_httpd is released under a BSD style copyright that unlike
|
||||
GPL is embedded developer friendly.
|
||||
|
||||
The server is designed to be run in one of two modes. The standard
|
||||
mode is a httpd server running in the background serving up a directory
|
||||
of html,gif,cgi whatever. Your traditional www server.
|
||||
|
||||
The "fetch" mode supports file transfer over httpd. This
|
||||
is best thought of as mate for fetch(1). This feature can be
|
||||
usefull to transfer a file from one host to another.
|
||||
|
||||
Simple_httpd has the ability to run CGI scripts. All CGI
|
||||
scripts must be located in ${DOCUMENT_ROOT}/cgi-bin. The
|
||||
server currently only sets 3 enviroment variables before calling
|
||||
the script.
|
||||
|
||||
CGI Enviroment variables are below:
|
||||
|
||||
SERVER_SOFTWARE = FreeBSD/PicoBSD
|
||||
REMOTE_HOST = client.canada_lower_taxes.com
|
||||
REMOTE_ADDR = 200.122.13.108
|
||||
|
||||
In most target applications for this server the extra DNS traffic from
|
||||
the remote_addr lookup will likely be on the local lan anyway and not
|
||||
on the other side of the internet. You can turn it off yourself in
|
||||
the code if you want to speed the whole process up. Be sure to turn
|
||||
it off for the logfile also.
|
||||
|
||||
How to use it?
|
||||
==============
|
||||
|
||||
Compile, and run:
|
||||
Compile with make, run as follows
|
||||
|
||||
simple_httpd <port>
|
||||
usage: simple_httpd [-vD]
|
||||
[-d directory]
|
||||
[-g grpid]
|
||||
[-l logfile]
|
||||
[-p port]
|
||||
or
|
||||
usage: simple_httpd [-p port] -f filename
|
||||
|
||||
If you're root, the document directory will be /httphome. If you're
|
||||
not, then first of all you need to use the <port> option (>1023).
|
||||
Then, the document root will be ${HOME}/httphome.
|
||||
-v
|
||||
Run the server verbose. Show the program options that will be used for this
|
||||
process. Will only show information during startup, no messages will
|
||||
be displayed while serving requests. In other words you can still
|
||||
daemonize without fear of output on stdout.
|
||||
|
||||
Log messages will be written out to /var/log/jhttpd.log .
|
||||
-D
|
||||
Do not daemonize. The server will not run in the background. It will
|
||||
stay attached to the tty. This is usefull for debugging. In this
|
||||
mode no log file is created. Logging info is to stdout.
|
||||
|
||||
This option is automatically selected if fetch option is selected.
|
||||
|
||||
-d directory
|
||||
The html document directory, if nothing is provided the default is
|
||||
/httphome if UID is root, otherwise document root is ${HOME}/public_html
|
||||
|
||||
-l logfile
|
||||
Set the logfile to use. Log messages will be written to /var/log/jhttpd.log
|
||||
if you are root and ${HOME}/jhttpd.log otherwise. If you don't want a
|
||||
log file try "-l /dev/null"
|
||||
|
||||
-p port
|
||||
Set the port httpd server will listen to. Default is port 80 if
|
||||
you are root and 1080 if you are not.
|
||||
|
||||
-f filename
|
||||
This is the only option needed to use the "fetch" feature. The file
|
||||
specified will be the ONLY file served to ANY GET request from a browser
|
||||
or fetch(1).
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
Standard Mode:
|
||||
--------------
|
||||
If you have the FreeBSD handbook installed on your machine and would
|
||||
like to serve it up over http for a quick look you could do this
|
||||
|
||||
simple_httpd -d /usr/share/doc/handbook -l /usr/tmp/jlog.txt -p 1088 -v
|
||||
|
||||
Any browser would be able to look at the handbook with
|
||||
http://whatever_host/handbook.html:1088
|
||||
|
||||
I'm using 1088 as the port since I already have apache running on port 80
|
||||
and port 1080 on my host.
|
||||
|
||||
Please note, the handbook is not installed by default in FreeBSD 3.x
|
||||
It must be installed from the ports collection first if you want to
|
||||
try this.
|
||||
|
||||
Another simple example is to browse your local ports collection:
|
||||
|
||||
cd /usr/ports
|
||||
make readmes #wait about 1 hour!
|
||||
simple_httpd -p 1080 -v -d /usr/ports
|
||||
|
||||
Then point your browser at http://whatever_host/README.html
|
||||
|
||||
Fetch Mode:
|
||||
--------------
|
||||
This is designed to be used in conjunction with fetch(3). It allows
|
||||
for easy transfer of files from one host to another without messy
|
||||
authentication or pathnames required with ftp. The file to be
|
||||
served up must be readable by the user running simple_httpd.
|
||||
This is not a magic way to avoid permissions and read files.
|
||||
|
||||
The daemon will only serve up ONE file. The file specified will
|
||||
be returned for every GET request regardless of what the browser
|
||||
asks for. This allows for on the fly naming.
|
||||
|
||||
sender# simple_httpd -f /usr/tmp/big_file.tgz
|
||||
receiver# fetch http://sender.com/Industrial_Secrets.tgz
|
||||
|
||||
big_file.tgz was transferred from one machine to another and renamed
|
||||
Industrial_Secrets.tgz at the same time.
|
||||
|
||||
Tunneling over other TCP ports. Choose something that firewall
|
||||
will probably pass. See /etc/services.
|
||||
|
||||
sender# simple_httpd -p 53 -f /usr/tmp/big_file.tgz
|
||||
receiver# fetch http://sender.com:53/Industrial_Secrets.tgz
|
||||
|
||||
To Do
|
||||
=====
|
||||
|
||||
Simple authentication would be very usefull[understatment].
|
||||
/etc/passwd or PAM would be nice.
|
||||
|
||||
I think a netmask option would be good. Most internet appliances
|
||||
probably want to restrict traffic to local ethernet anyway.
|
||||
ie: Allow anything from my class C.
|
||||
|
||||
The server always has 1 zombie process hanging around when it
|
||||
runs as a daemon. Should fix so that it doesn't happen.
|
||||
|
||||
Anything to make it faster!
|
||||
|
||||
Man page
|
||||
|
||||
If anyone has any improvements or ways to easily implement something
|
||||
please let me <wlloyd@slap.net> know. If you make some neat embedded
|
||||
device with PicoBSD I want to know too!
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
This program was contributed by Marc Nicholas <marc@netstor.com>
|
||||
This program was originally contributed by Marc Nicholas <marc@netstor.com>
|
||||
|
||||
$Id: README,v 1.2.2.1 1999/02/05 12:21:41 abial Exp $
|
||||
Major rewrite by William Lloyd <wlloyd@slap.net>
|
||||
|
||||
$Id:$
|
||||
|
@ -1,9 +1,11 @@
|
||||
/*-
|
||||
* SimpleHTTPd v1.0 - a very small, barebones HTTP server
|
||||
* Simple_HTTPd v1.1 - a very small, barebones HTTP server
|
||||
*
|
||||
* Copyright (c) 1998-1999 Marc Nicholas <marc@netstor.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Major rewrite by William Lloyd <wlloyd@slap.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
@ -25,32 +27,60 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: simple_httpd.c,v 1.2.2.1 1999/02/05 12:21:41 abial Exp $
|
||||
* $Id:$
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <netdb.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int http_sock, con_sock;
|
||||
int http_port = 80;
|
||||
struct sockaddr_in source;
|
||||
char homedir[100];
|
||||
char *adate();
|
||||
struct hostent *hst;
|
||||
int daemonize = 1;
|
||||
int verbose = 0;
|
||||
int http_sock, con_sock;
|
||||
|
||||
char fetch_mode[100];
|
||||
char homedir[100];
|
||||
char logfile[80];
|
||||
char *adate();
|
||||
|
||||
struct hostent *hst;
|
||||
struct sockaddr_in source;
|
||||
|
||||
/* HTTP basics */
|
||||
static char httpd_server_ident[] = "Server: FreeBSD/PicoBSD simple_httpd 1.1\r";
|
||||
|
||||
static char http_200[] = "HTTP/1.0 200 OK\r";
|
||||
|
||||
/* Two parts, HTTP Header and then HTML */
|
||||
static char *http_404[2] =
|
||||
{"HTTP/1.0 404 Not found\r\n",
|
||||
"<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY><H1>Error 404</H1>\
|
||||
Not found - file doesn't exist or you do not have permission.\n</BODY></HTML>\r\n"
|
||||
};
|
||||
|
||||
static char *http_405[2] =
|
||||
{"HTTP/1.0 405 Method Not allowed\r\nAllow: GET,HEAD\r\n",
|
||||
"<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY><H1>Error 405</H1>\
|
||||
This server only supports GET and HEAD requests.\n</BODY></HTML>\r\n"
|
||||
};
|
||||
|
||||
/*
|
||||
* Only called on initial invocation
|
||||
*/
|
||||
void
|
||||
init_servconnection(void)
|
||||
{
|
||||
@ -69,10 +99,13 @@ init_servconnection(void)
|
||||
perror("bind socket");
|
||||
exit(1);
|
||||
}
|
||||
printf("simpleHTTPd running on %d port\n",http_port);
|
||||
if (verbose) printf("simple_httpd\n",http_port);
|
||||
}
|
||||
|
||||
attenteconnection(void)
|
||||
/*
|
||||
* Wait here until we see an incoming http request
|
||||
*/
|
||||
wait_connection(void)
|
||||
{
|
||||
int lg;
|
||||
|
||||
@ -85,7 +118,10 @@ attenteconnection(void)
|
||||
}
|
||||
}
|
||||
|
||||
outdate()
|
||||
/*
|
||||
* Print timestamp for HTTP HEAD and GET
|
||||
*/
|
||||
http_date()
|
||||
{
|
||||
time_t tl;
|
||||
char buff[50];
|
||||
@ -93,110 +129,114 @@ outdate()
|
||||
tl = time(NULL);
|
||||
strftime(buff, 50, "Date: %a, %d %h %Y %H:%M:%S %Z\r\n", gmtime(&tl));
|
||||
write(con_sock, buff, strlen(buff));
|
||||
//return(buff);
|
||||
}
|
||||
|
||||
char *rep_err_nget[2] = {"<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY><H1>Error 405</H1>\
|
||||
This server is supports only GET and HEAD requests\n</BODY></HTML>\r\n",
|
||||
"HTTP/1.0 405 Method Not allowed\r\nAllow: GET,HEAD\r\nServer: jhttpd\r\n"};
|
||||
|
||||
char *rep_err_acc[2] = {"<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY><H1>Error 404</H1>\
|
||||
Not found - file doesn't exist or is read protected\n</BODY></HTML>\r\n",
|
||||
"HTTP/1.0 404 Not found\r\nServer: jhttpd\r\n"};
|
||||
|
||||
outerror(char **rep, int http1) /* ÷ÙÄÙÞÁ ÏÛÉÂËÉ ËÌÉÅÎÔÕ × html- ×ÉÄÅ */
|
||||
/*
|
||||
* Send data to the open socket
|
||||
*/
|
||||
http_output(char *html)
|
||||
{
|
||||
|
||||
if (http1) {
|
||||
write(con_sock, rep[1], strlen(rep[1]));
|
||||
outdate();
|
||||
write(con_sock, "\r\n", 2);
|
||||
}
|
||||
write(con_sock, rep[0], strlen(rep[0]));
|
||||
write(con_sock, html, strlen(html));
|
||||
write(con_sock, "\r\n", 2);
|
||||
}
|
||||
|
||||
char rep_head[] = "HTTP/1.0 200 OK\r\nServer: simpleHTTPD\r\n";
|
||||
|
||||
traite_req()
|
||||
/*
|
||||
* Create and write the log information to file
|
||||
* Log file format is one line per entry
|
||||
*/
|
||||
log_line(char *req)
|
||||
{
|
||||
char buff[8192];
|
||||
int fd, lg, cmd, http1, i;
|
||||
char *filename, *c;
|
||||
struct stat statres;
|
||||
char req[1024];
|
||||
char logfile[80];
|
||||
char log_buff[256];
|
||||
char msg[1024];
|
||||
char *p,
|
||||
*par;
|
||||
long addr;
|
||||
FILE *log;
|
||||
char env_host[80], env_addr[80];
|
||||
long addr;
|
||||
FILE *log;
|
||||
|
||||
strcpy(log_buff,inet_ntoa(source.sin_addr));
|
||||
sprintf(env_addr, "REMOTE_ADDR=%s",log_buff);
|
||||
|
||||
addr=inet_addr(log_buff);
|
||||
|
||||
strcpy(msg,adate());
|
||||
strcat(msg," ");
|
||||
hst=gethostbyaddr((char*) &addr, 4, AF_INET);
|
||||
|
||||
/* If DNS hostname exists */
|
||||
if (hst) {
|
||||
strcat(msg,hst->h_name);
|
||||
sprintf(env_host, "REMOTE_HOST=%s",hst->h_name);
|
||||
}
|
||||
strcat(msg," (");
|
||||
strcat(msg,log_buff);
|
||||
strcat(msg,") ");
|
||||
strcat(msg,req);
|
||||
|
||||
if (daemonize) {
|
||||
log=fopen(logfile,"a");
|
||||
fprintf(log,"%s\n",msg);
|
||||
fclose(log);
|
||||
} else
|
||||
printf("%s\n",msg);
|
||||
|
||||
/* This is for CGI scripts */
|
||||
putenv(env_addr);
|
||||
putenv(env_host);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have a connection. Identify what type of request GET, HEAD, CGI, etc
|
||||
* and do what needs to be done
|
||||
*/
|
||||
http_request()
|
||||
{
|
||||
int fd, lg, ld, i;
|
||||
int cmd = 0;
|
||||
int http1 = 0;
|
||||
char *p, *par;
|
||||
char *filename, *c;
|
||||
struct stat file_status;
|
||||
char req[1024];
|
||||
char msg[1024];
|
||||
char buff[8192];
|
||||
|
||||
lg = read(con_sock, req, 1024);
|
||||
|
||||
if (p=strstr(req,"\n")) *p=0;
|
||||
if (p=strstr(req,"\r")) *p=0;
|
||||
|
||||
if (geteuid())
|
||||
{
|
||||
strcpy(logfile,getenv("HOME"));
|
||||
strcat(logfile,"/");
|
||||
strcat(logfile,"jhttp.log");
|
||||
}
|
||||
else strcpy(logfile,"/var/log/jhttpd.log");
|
||||
|
||||
if ( access(logfile,W_OK))
|
||||
{
|
||||
lg=creat (logfile,O_WRONLY);
|
||||
chmod (logfile,00600);
|
||||
close(lg);
|
||||
}
|
||||
|
||||
strcpy(buff,inet_ntoa(source.sin_addr));
|
||||
|
||||
addr=inet_addr(buff);
|
||||
|
||||
strcpy(msg,adate());
|
||||
strcat(msg," ");
|
||||
hst=gethostbyaddr((char*) &addr, 4, AF_INET);
|
||||
if (hst) strcat(msg,hst->h_name);
|
||||
strcat(msg," (");
|
||||
strcat(msg,buff);
|
||||
strcat(msg,") ");
|
||||
strcat(msg,req);
|
||||
|
||||
log=fopen(logfile,"a");
|
||||
fprintf(log,"%s\n",msg);
|
||||
fclose(log);
|
||||
log_line(req);
|
||||
|
||||
c = strtok(req, " ");
|
||||
|
||||
/* Error msg if request is nothing */
|
||||
if (c == NULL) {
|
||||
outerror(rep_err_nget, 0);
|
||||
goto error;
|
||||
http_output(http_404[0]);
|
||||
http_output(http_404[1]);
|
||||
goto end_request;
|
||||
}
|
||||
cmd = 0;
|
||||
if (strncmp(c, "GET", 3) == 0)
|
||||
cmd = 1;
|
||||
if (strncmp(c, "HEAD", 4) == 0) {
|
||||
cmd = 2;
|
||||
|
||||
if (strncmp(c, "GET", 3) == 0) cmd = 1;
|
||||
if (strncmp(c, "HEAD", 4) == 0) cmd = 2;
|
||||
|
||||
/* Do error msg for any other type of request */
|
||||
if (cmd == 0) {
|
||||
http_output(http_405[0]);
|
||||
http_output(http_405[1]);
|
||||
goto end_request;
|
||||
}
|
||||
|
||||
filename = strtok(NULL, " ");
|
||||
|
||||
http1 = 0;
|
||||
c = strtok(NULL, " ");
|
||||
if (c != NULL && strncmp(c, "HTTP", 4) == 0)
|
||||
http1 = 1;
|
||||
|
||||
if (cmd == 0) {
|
||||
outerror(rep_err_nget, http1);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (fetch_mode[0] != NULL) strcpy(filename,fetch_mode);
|
||||
if (filename == NULL ||
|
||||
strlen(filename)==1) filename="/index.html";
|
||||
|
||||
while (filename[0]== '/') filename++;
|
||||
|
||||
/**/
|
||||
while (filename[0]== '/') filename++;
|
||||
|
||||
/* CGI handling. Untested */
|
||||
if (!strncmp(filename,"cgi-bin/",8))
|
||||
{
|
||||
par=0;
|
||||
@ -206,152 +246,224 @@ traite_req()
|
||||
par++;
|
||||
}
|
||||
if (access(filename,X_OK)) goto conti;
|
||||
stat (filename,&statres);
|
||||
if (setuid(statres.st_uid)) return(0);
|
||||
if (seteuid(statres.st_uid)) return(0);
|
||||
stat (filename,&file_status);
|
||||
if (setuid(file_status.st_uid)) return(0);
|
||||
if (seteuid(file_status.st_uid)) return(0);
|
||||
if (!fork())
|
||||
{
|
||||
close(1);
|
||||
dup(con_sock);
|
||||
printf("HTTP/1.0 200 OK\nContent-type: text/html\n\n\n");
|
||||
execlp (filename,filename,par,0);
|
||||
//printf("HTTP/1.0 200 OK\nContent-type: text/html\n\n\n");
|
||||
printf("HTTP/1.0 200 OK\r\n");
|
||||
/* Plug in environment variable, others in log_line */
|
||||
putenv("SERVER_SOFTWARE=FreeBSD/PicoBSD");
|
||||
|
||||
execlp (filename,filename,par,0);
|
||||
}
|
||||
wait(&i);
|
||||
return(0);
|
||||
}
|
||||
conti:
|
||||
if (filename == NULL) {
|
||||
outerror(rep_err_acc, http1);
|
||||
goto error;
|
||||
http_output(http_405[0]);
|
||||
http_output(http_405[1]);
|
||||
goto end_request;
|
||||
}
|
||||
/* interdit les .. dans le path */
|
||||
/* End of CGI handling */
|
||||
|
||||
/* Reject any request with '..' in it, bad hacker */
|
||||
c = filename;
|
||||
while (*c != '\0')
|
||||
if (c[0] == '.' && c[1] == '.') {
|
||||
outerror(rep_err_acc, http1);
|
||||
goto error;
|
||||
} else
|
||||
c++;
|
||||
|
||||
if (c[0] == '.' && c[1] == '.') {
|
||||
http_output(http_404[0]);
|
||||
http_output(http_404[1]);
|
||||
goto end_request;
|
||||
} else
|
||||
c++;
|
||||
|
||||
/* Open filename */
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
outerror(rep_err_acc, http1);
|
||||
goto error;
|
||||
http_output(http_404[0]);
|
||||
http_output(http_404[1]);
|
||||
goto end_request;
|
||||
}
|
||||
if (fstat(fd, &statres) < 0) {
|
||||
outerror(rep_err_acc, http1);
|
||||
goto error;
|
||||
|
||||
/* Get file status information */
|
||||
if (fstat(fd, &file_status) < 0) {
|
||||
http_output(http_404[0]);
|
||||
http_output(http_404[1]);
|
||||
goto end_request;
|
||||
}
|
||||
|
||||
/* Is it a regular file? */
|
||||
if (!S_ISREG(file_status.st_mode)) {
|
||||
http_output(http_404[0]);
|
||||
http_output(http_404[1]);
|
||||
goto end_request;
|
||||
}
|
||||
if (!S_ISREG(statres.st_mode))
|
||||
{
|
||||
outerror(rep_err_acc, http1);
|
||||
goto error;
|
||||
}
|
||||
if (http1) {
|
||||
char buff[50];
|
||||
time_t tl;
|
||||
|
||||
write(con_sock, rep_head, strlen(rep_head));
|
||||
sprintf(buff, "Content-length: %d\r\n", statres.st_size);
|
||||
write(con_sock, buff, strlen(buff));
|
||||
outdate();
|
||||
/* Past this point we are serving either a GET or HEAD */
|
||||
/* Print all the header info */
|
||||
http_output(http_200);
|
||||
http_output(httpd_server_ident);
|
||||
http_date();
|
||||
|
||||
if (strstr(filename,"."))
|
||||
{
|
||||
strcpy(buff,"Content-type: ");
|
||||
strcat(buff,strstr(filename,".")+1);
|
||||
strcat(buff,"\r\n");
|
||||
write(con_sock,buff,strlen(buff));
|
||||
}
|
||||
sprintf(buff, "Content-length: %d\r\n", file_status.st_size);
|
||||
|
||||
if (strstr(filename,".txt"))
|
||||
{
|
||||
strcpy(buff,"Content-type: text/plain\r\n");
|
||||
write(con_sock, buff, strlen(buff));
|
||||
}
|
||||
|
||||
if (strstr(filename,".html") ||
|
||||
strstr(filename,".htm"))
|
||||
{
|
||||
strcpy(buff,"Content-type: text/html\r\n");
|
||||
write(con_sock, buff, strlen(buff));
|
||||
}
|
||||
|
||||
if (strstr(filename,".gif"))
|
||||
{
|
||||
strcpy(buff,"Content-type: image/gif\r\n");
|
||||
write(con_sock, buff, strlen(buff));
|
||||
}
|
||||
|
||||
if (strstr(filename,".jpg"))
|
||||
{
|
||||
strcpy(buff,"Content-type: image/jpeg\r\n");
|
||||
write(con_sock, buff, strlen(buff));
|
||||
}
|
||||
|
||||
strftime(buff, 50, "Last-Modified: %a, %d %h %Y %H:%M:%S %Z\r\n\r\n", gmtime(&statres.st_mtime));
|
||||
write(con_sock, buff, strlen(buff));
|
||||
if (strstr(filename,".txt")) {
|
||||
strcpy(buff,"Content-type: text/plain\r\n");
|
||||
} else if (strstr(filename,".html") || strstr(filename,".htm")) {
|
||||
strcpy(buff,"Content-type: text/html\r\n");
|
||||
} else if (strstr(filename,".gif")) {
|
||||
strcpy(buff,"Content-type: image/gif\r\n");
|
||||
} else if (strstr(filename,".jpg")) {
|
||||
strcpy(buff,"Content-type: image/jpeg\r\n");
|
||||
} else {
|
||||
/* Take a guess at content if we don't have something already */
|
||||
strcpy(buff,"Content-type: ");
|
||||
strcat(buff,strstr(filename,".")+1);
|
||||
strcat(buff,"\r\n");
|
||||
}
|
||||
write(con_sock, buff, strlen(buff));
|
||||
|
||||
strftime(buff, 50, "Last-Modified: %a, %d %h %Y %H:%M:%S %Z\r\n\r\n", gmtime(&file_status.st_mtime));
|
||||
write(con_sock, buff, strlen(buff));
|
||||
|
||||
/* Send data only if GET request */
|
||||
if (cmd == 1) {
|
||||
while (lg = read(fd, buff, 8192))
|
||||
write(con_sock, buff, lg);
|
||||
while (lg = read(fd, buff, 8192))
|
||||
write(con_sock, buff, lg);
|
||||
}
|
||||
|
||||
error:
|
||||
end_request:
|
||||
close(fd);
|
||||
close(con_sock);
|
||||
|
||||
}
|
||||
|
||||
|
||||
main(int argc, char **argv)
|
||||
/*
|
||||
* Simple httpd server for use in PicoBSD or other embedded application.
|
||||
* Should satisfy simple httpd needs. For more demanding situations
|
||||
* apache is probably a better (but much larger) choice.
|
||||
*/
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int lg;
|
||||
char hello[100];
|
||||
|
||||
if (argc<2 && geteuid())
|
||||
{
|
||||
printf("Usage: simple_htppd <port>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (argc>=2) http_port = atoi(argv[1]);
|
||||
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
int bflag, ch, fd, ld;
|
||||
int lg;
|
||||
int httpd_group = 65534;
|
||||
pid_t server_pid;
|
||||
|
||||
/* Default for html directory */
|
||||
strcpy (homedir,getenv("HOME"));
|
||||
if (!geteuid()) strcpy (homedir,"/httphome");
|
||||
else strcat (homedir,"/httphome");
|
||||
|
||||
strcpy(hello,homedir);
|
||||
strcat(hello,"/0hello.html");
|
||||
/* Defaults for log file */
|
||||
if (geteuid()) {
|
||||
strcpy(logfile,getenv("HOME"));
|
||||
strcat(logfile,"/");
|
||||
strcat(logfile,"jhttp.log");
|
||||
} else
|
||||
strcpy(logfile,"/var/log/jhttpd.log");
|
||||
|
||||
/* Parse command line arguments */
|
||||
while ((ch = getopt(argc, argv, "d:f:g:l:p:vDh")) != -1)
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
strcpy(homedir,optarg);
|
||||
break;
|
||||
case 'f':
|
||||
daemonize = 0;
|
||||
verbose = 1;
|
||||
strcpy(fetch_mode,optarg);
|
||||
break;
|
||||
case 'g':
|
||||
httpd_group = atoi(optarg);
|
||||
break;
|
||||
case 'l':
|
||||
strcpy(logfile,optarg);
|
||||
break;
|
||||
case 'p':
|
||||
http_port = atoi(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
case 'D':
|
||||
daemonize = 0;
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
default:
|
||||
printf("usage: simple_httpd [[-d directory][-g grpid][-l logfile][-p port][-vD]]\n");
|
||||
exit(1);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/* Not running as root and no port supplied, assume 1080 */
|
||||
if ((http_port == 80) && geteuid()) {
|
||||
http_port = 1080;
|
||||
}
|
||||
|
||||
/* Do we really have rights in the html directory? */
|
||||
if (fetch_mode[0] == NULL) {
|
||||
if (chdir(homedir)) {
|
||||
perror("chdir");
|
||||
puts(homedir);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create log file if it doesn't exit */
|
||||
if ((access(logfile,W_OK)) && daemonize) {
|
||||
ld = open (logfile,O_WRONLY);
|
||||
chmod (logfile,00600);
|
||||
close(ld);
|
||||
}
|
||||
|
||||
if (chdir(homedir))
|
||||
{
|
||||
perror("chdir");
|
||||
puts(homedir);
|
||||
exit(1);
|
||||
}
|
||||
init_servconnection();
|
||||
|
||||
if (fork()) exit(0);
|
||||
|
||||
setpgrp(0,65534);
|
||||
signal(SIGQUIT, SIG_IGN);
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
if (verbose) {
|
||||
printf("Server started with options \n");
|
||||
printf("port: %d\n",http_port);
|
||||
if (fetch_mode[0] == NULL) printf("html home: %s\n",homedir);
|
||||
if (daemonize) printf("logfile: %s\n",logfile);
|
||||
}
|
||||
|
||||
if (listen(http_sock,100) < 0) exit(1);
|
||||
/* httpd is spawned */
|
||||
if (daemonize) {
|
||||
if (server_pid = fork()) {
|
||||
wait3(0,WNOHANG,0);
|
||||
if (verbose) printf("pid: %d\n",server_pid);
|
||||
exit(0);
|
||||
}
|
||||
wait3(0,WNOHANG,0);
|
||||
}
|
||||
|
||||
if (fetch_mode[0] == NULL) setpgrp(0,httpd_group);
|
||||
|
||||
/* How many connections do you want?
|
||||
* Keep this lower than the available number of processes
|
||||
*/
|
||||
if (listen(http_sock,15) < 0) exit(1);
|
||||
|
||||
label:
|
||||
attenteconnection();
|
||||
if (fork())
|
||||
{
|
||||
close(con_sock);
|
||||
goto label;
|
||||
}
|
||||
alarm(1800);
|
||||
traite_req();
|
||||
exit(0);
|
||||
}
|
||||
wait_connection();
|
||||
|
||||
if (fork()) {
|
||||
wait3(0,WNOHANG,0);
|
||||
close(con_sock);
|
||||
goto label;
|
||||
}
|
||||
|
||||
http_request();
|
||||
|
||||
wait3(0,WNOHANG,0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
char *adate()
|
||||
|
Loading…
Reference in New Issue
Block a user