aboutsummaryrefslogtreecommitdiffstats
path: root/release/picobsd/tinyware/simple_httpd/simple_httpd.c
diff options
context:
space:
mode:
authorKyle Evans <kevans@FreeBSD.org>2019-10-01 14:55:16 +0000
committerKyle Evans <kevans@FreeBSD.org>2019-10-01 14:55:16 +0000
commit2d0a92c9ab15c6df408f4fe864cee256e1dc9f8a (patch)
treec38b17a86d870f51fb9aa4b603af5977a80b02fd /release/picobsd/tinyware/simple_httpd/simple_httpd.c
parent935dbbeb8bfcbe0a87afa36b2a2fc880c818e565 (diff)
downloadsrc-2d0a92c9ab15c6df408f4fe864cee256e1dc9f8a.tar.gz
src-2d0a92c9ab15c6df408f4fe864cee256e1dc9f8a.zip
Move simple_httpd out of picobsd, add HTTPD option (default OFF)
picobsd/tinyware has had this compact HTTPD server for a long time, and some people do use it. Move it out into usr.sbin well in advance of any action being taken on picobsd. This has been gated behind an HTTPD option defaulted to *off*, primarily for two reasons: 1.) This code likely needs a good audit, as it's been living off in picobsd land for a long time, and 2.) We don't currently ship an httpd and this may not be a welcome surprise. Reviewed by: eugen Differential Revision: https://reviews.freebsd.org/D21724
Notes
Notes: svn path=/head/; revision=352927
Diffstat (limited to 'release/picobsd/tinyware/simple_httpd/simple_httpd.c')
-rw-r--r--release/picobsd/tinyware/simple_httpd/simple_httpd.c501
1 files changed, 0 insertions, 501 deletions
diff --git a/release/picobsd/tinyware/simple_httpd/simple_httpd.c b/release/picobsd/tinyware/simple_httpd/simple_httpd.c
deleted file mode 100644
index 768b1ce4c838..000000000000
--- a/release/picobsd/tinyware/simple_httpd/simple_httpd.c
+++ /dev/null
@@ -1,501 +0,0 @@
-/*-
- * 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:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <fcntl.h>
-#include <netdb.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-static int http_port = 80;
-static int daemonize = 1;
-static int verbose = 0;
-static int http_sock, con_sock;
-
-static const char *fetch_mode = NULL;
-static char homedir[100];
-static char logfile[80];
-static char *adate(void);
-static void init_servconnection(void);
-static void http_date(void);
-static void http_output(const char *html);
-static void http_request(void);
-static void log_line(char *req);
-static void wait_connection(void);
-
-static struct hostent *hst;
-static 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";
-
-static const char *default_mime_type = "application/octet-stream";
-
-static const char *mime_type[][2] = {
- { "txt", "text/plain" },
- { "htm", "text/html" },
- { "html", "text/html" },
- { "gif", "image/gif" },
- { "jpg", "image/jpeg" },
- { "mp3", "audio/mpeg" }
-};
-
-static const int mime_type_max = sizeof(mime_type) / sizeof(mime_type[0]) - 1;
-
-/* Two parts, HTTP Header and then HTML */
-static const 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 const 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
- */
-static void
-init_servconnection(void)
-{
- struct sockaddr_in server;
-
- /* Create a socket */
- http_sock = socket(AF_INET, SOCK_STREAM, 0);
- if (http_sock < 0) {
- perror("socket");
- exit(1);
- }
- server.sin_family = AF_INET;
- server.sin_port = htons(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 (verbose) printf("simple_httpd:%d\n",http_port);
-}
-
-/*
- * Wait here until we see an incoming http request
- */
-static void
-wait_connection(void)
-{
- socklen_t lg;
-
- lg = sizeof(struct sockaddr_in);
-
- con_sock = accept(http_sock, (struct sockaddr *) & source, &lg);
- if (con_sock <= 0) {
- perror("accept");
- exit(1);
- }
-}
-
-/*
- * Print timestamp for HTTP HEAD and GET
- */
-static void
-http_date(void)
-{
- time_t tl;
- char buff[50];
-
- 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); */
-}
-
-/*
- * Send data to the open socket
- */
-static void
-http_output(const char *html)
-{
- write(con_sock, html, strlen(html));
- write(con_sock, "\r\n", 2);
-}
-
-
-/*
- * Create and write the log information to file
- * Log file format is one line per entry
- */
-static void
-log_line(char *req)
-{
- char log_buff[256];
- char msg[1024];
- 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
- */
-static void
-http_request(void)
-{
- int fd, lg, i;
- int cmd = 0;
- char *p, *par;
- const char *filename, *c, *ext, *type;
- struct stat file_status;
- char req[1024];
- char buff[8192];
-
- lg = read(con_sock, req, 1024);
-
- if ((p=strstr(req,"\n"))) *p=0;
- if ((p=strstr(req,"\r"))) *p=0;
-
- log_line(req);
-
- c = strtok(req, " ");
-
- /* Error msg if request is nothing */
- if (c == NULL) {
- http_output(http_404[0]);
- http_output(http_404[1]);
- goto end_request;
- }
-
- 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, " ");
-
- c = strtok(NULL, " ");
- if (fetch_mode != NULL) filename=fetch_mode;
- if (filename == NULL ||
- strlen(filename)==1) filename="/index.html";
-
- while (filename[0]== '/') filename++;
-
- /* CGI handling. Untested */
- if (!strncmp(filename,"cgi-bin/",8))
- {
- par=0;
- if ((par=strstr(filename,"?")))
- {
- *par=0;
- par++;
- }
- if (access(filename,X_OK)) goto conti;
- stat (filename,&file_status);
- if (setuid(file_status.st_uid)) return;
- if (seteuid(file_status.st_uid)) return;
- if (!fork())
- {
- close(1);
- dup(con_sock);
- /*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 */
- setenv("SERVER_SOFTWARE", "FreeBSD/PicoBSD", 1);
-
- execlp (filename,filename,par,(char *)0);
- }
- wait(&i);
- return;
- }
- conti:
- if (filename == NULL) {
- http_output(http_405[0]);
- http_output(http_405[1]);
- goto end_request;
- }
- /* End of CGI handling */
-
- /* Reject any request with '..' in it, bad hacker */
- c = filename;
- while (*c != '\0')
- 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) {
- http_output(http_404[0]);
- http_output(http_404[1]);
- goto end_request;
- }
-
- /* Get file status information */
- if (fstat(fd, &file_status) < 0) {
- http_output(http_404[0]);
- http_output(http_404[1]);
- goto end_request2;
- }
-
- /* Is it a regular file? */
- if (!S_ISREG(file_status.st_mode)) {
- http_output(http_404[0]);
- http_output(http_404[1]);
- goto end_request2;
- }
-
- /* 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();
-
- sprintf(buff, "Content-length: %jd\r\n", (intmax_t)file_status.st_size);
- write(con_sock, buff, strlen(buff));
-
- strcpy(buff, "Content-type: ");
- type = default_mime_type;
- if ((ext = strrchr(filename, '.')) != NULL) {
- for (i = mime_type_max; i >= 0; i--)
- if (strcmp(ext + 1, mime_type[i][0]) == 0) {
- type = mime_type[i][1];
- break;
- }
- }
- strcat(buff, type);
- http_output(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)) > 0)
- write(con_sock, buff, lg);
- }
-
-end_request2:
- close(fd);
-end_request:
- close(con_sock);
-
-}
-
-/*
- * 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.
- */
-int
-main(int argc, char *argv[])
-{
- int ch, ld;
- pid_t httpd_group = 65534;
- pid_t server_pid;
-
- /* Default for html directory */
- strcpy (homedir,getenv("HOME"));
- if (!geteuid()) strcpy (homedir,"/httphome");
- else strcat (homedir,"/httphome");
-
- /* 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;
- 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 == 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);
- }
-
- init_servconnection();
-
- if (verbose) {
- printf("Server started with options \n");
- printf("port: %d\n",http_port);
- if (fetch_mode == NULL) printf("html home: %s\n",homedir);
- if (daemonize) printf("logfile: %s\n",logfile);
- }
-
- /* httpd is spawned */
- if (daemonize) {
- if ((server_pid = fork()) != 0) {
- wait3(0,WNOHANG,0);
- if (verbose) printf("pid: %d\n",server_pid);
- exit(0);
- }
- wait3(0,WNOHANG,0);
- }
-
- if (fetch_mode == NULL)
- setpgrp((pid_t)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:
- wait_connection();
-
- if (fork()) {
- wait3(0,WNOHANG,0);
- close(con_sock);
- goto label;
- }
-
- http_request();
-
- wait3(0,WNOHANG,0);
- exit(0);
-}
-
-
-char *
-adate(void)
-{
- static char out[50];
- time_t now;
- struct tm *t;
- time(&now);
- t = localtime(&now);
- sprintf(out, "%02d:%02d:%02d %02d/%02d/%02d",
- t->tm_hour, t->tm_min, t->tm_sec,
- t->tm_mday, t->tm_mon+1, t->tm_year );
- return out;
-}