summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSkywalkerSW5 <skywalkersw5@yahoo.com>2021-12-18 20:07:34 +0000
committerSkywalkerSW5 <skywalkersw5@yahoo.com>2021-12-18 20:07:34 +0000
commitd411b6e3cb33043de0943f6066bea77a7a962823 (patch)
treed5a2fe8df8046bcf9cd3ac8b2429f628c13c78ee
release
-rw-r--r--LICENSE.txt8
-rw-r--r--Makefile5
-rw-r--r--README.md27
-rwxr-xr-xittpdbin0 -> 17808 bytes
-rw-r--r--ittpd.c195
5 files changed, 235 insertions, 0 deletions
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..7c02228
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,8 @@
+The MIT License (MIT)
+Copyright © 2021 SkywalkerSW5
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..cc11bb5
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,5 @@
+all: ittpd
+ittpd:
+ c99 -DLINUX ittpd.c -o ittpd
+clean:
+ rm ittpd
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9b42b35
--- /dev/null
+++ b/README.md
@@ -0,0 +1,27 @@
+# ittpd
+A fork of IBM's nweb, with support for CSS and JavaScript
+
+## Usage
+ittpd can take a port number, and a directory where an index.html file is.
+
+Example:
+
+```./ittpd 8181 /server/website```
+
+## Supports
+
+ittpd supports these formats:
+
+gif, jpg, jpeg, png, ico, zip, gz, tar, htm, html, css, js, json
+
+It doesn't support Java or CGI.
+
+It also won't run in /, /etc/, /bin, /lib, /tmp, /usr, /dev, /sbin.
+
+## License
+
+I can't find the original license for this program, so until I do I will just put this under MIT.
+
+## Credits
+
+Originally created by Nigel Griffiths (nag@ik.ibm.com) \ No newline at end of file
diff --git a/ittpd b/ittpd
new file mode 100755
index 0000000..e54f058
--- /dev/null
+++ b/ittpd
Binary files differ
diff --git a/ittpd.c b/ittpd.c
new file mode 100644
index 0000000..d4bfa37
--- /dev/null
+++ b/ittpd.c
@@ -0,0 +1,195 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#define VERSION 23
+#define BUFSIZE 8096
+#define ERROR 42
+#define LOG 44
+#define FORBIDDEN 403
+#define NOTFOUND 404
+
+struct {
+ char *ext;
+ char *filetype;
+} extensions [] = {
+ {"gif", "image/gif" },
+ {"jpg", "image/jpg" },
+ {"jpeg","image/jpeg"},
+ {"png", "image/png" },
+ {"ico", "image/ico" },
+ {"zip", "image/zip" },
+ {"gz", "image/gz" },
+ {"tar", "image/tar" },
+ {"htm", "text/html" },
+ {"html","text/html" },
+ {"css", "text/css" },
+ {"js", "text/js" },
+ {"json","application/json" },
+ {0,0} };
+
+void logger(int type, char *s1, char *s2, int socket_fd)
+{
+ int fd ;
+ char logbuffer[BUFSIZE*2];
+
+ switch (type) {
+ case ERROR: (void)sprintf(logbuffer,"ERROR: %s:%s Errno=%d exiting pid=%d",s1, s2, errno,getpid());
+ break;
+ case FORBIDDEN:
+ (void)write(socket_fd, "HTTP/1.1 403 Forbidden\nContent-Length: 185\nConnection: close\nContent-Type: text/html\n\n<html><head>\n<title>403 Forbidden</title>\n</head><body>\n<h1>Forbidden</h1>\nThe requested URL, file type or operation is not allowed on this simple static file webserver.\n</body></html>\n",271);
+ (void)sprintf(logbuffer,"FORBIDDEN: %s:%s",s1, s2);
+ break;
+ case NOTFOUND:
+ (void)write(socket_fd, "HTTP/1.1 404 Not Found\nContent-Length: 136\nConnection: close\nContent-Type: text/html\n\n<html><head>\n<title>404 Not Found</title>\n</head><body>\n<h1>Not Found</h1>\nThe requested URL was not found on this server.\n</body></html>\n",224);
+ (void)sprintf(logbuffer,"NOT FOUND: %s:%s",s1, s2);
+ break;
+ case LOG: (void)sprintf(logbuffer," INFO: %s:%s:%d",s1, s2,socket_fd); break;
+ }
+ /* No checks here, nothing can be done with a failure anyway */
+ if((fd = open("ittpd.log", O_CREAT| O_WRONLY | O_APPEND,0644)) >= 0) {
+ (void)write(fd,logbuffer,strlen(logbuffer));
+ (void)write(fd,"\n",1);
+ (void)close(fd);
+ }
+ if(type == ERROR || type == NOTFOUND || type == FORBIDDEN) exit(3);
+}
+
+/* this is a child web server process, so we can exit on errors */
+void web(int fd, int hit)
+{
+ int j, file_fd, buflen;
+ long i, ret, len;
+ char * fstr;
+ static char buffer[BUFSIZE+1]; /* static so zero filled */
+
+ ret =read(fd,buffer,BUFSIZE); /* read Web request in one go */
+ if(ret == 0 || ret == -1) { /* read failure stop now */
+ logger(FORBIDDEN,"failed to read browser request","",fd);
+ }
+ if(ret > 0 && ret < BUFSIZE) /* return code is valid chars */
+ buffer[ret]=0; /* terminate the buffer */
+ else buffer[0]=0;
+ for(i=0;i<ret;i++) /* remove CF and LF characters */
+ if(buffer[i] == '\r' || buffer[i] == '\n')
+ buffer[i]='*';
+ logger(LOG,"request",buffer,hit);
+ if( strncmp(buffer,"GET ",4) && strncmp(buffer,"get ",4) ) {
+ logger(FORBIDDEN,"Only simple GET operation supported",buffer,fd);
+ }
+ for(i=4;i<BUFSIZE;i++) { /* null terminate after the second space to ignore extra stuff */
+ if(buffer[i] == ' ') { /* string is "GET URL " +lots of other stuff */
+ buffer[i] = 0;
+ break;
+ }
+ }
+ for(j=0;j<i-1;j++) /* check for illegal parent directory use .. */
+ if(buffer[j] == '.' && buffer[j+1] == '.') {
+ logger(FORBIDDEN,"Parent directory (..) path names not supported",buffer,fd);
+ }
+ if( !strncmp(&buffer[0],"GET /\0",6) || !strncmp(&buffer[0],"get /\0",6) ) /* convert no filename to index file */
+ (void)strcpy(buffer,"GET /index.html");
+
+ /* work out the file type and check we support it */
+ buflen=strlen(buffer);
+ fstr = (char *)0;
+ for(i=0;extensions[i].ext != 0;i++) {
+ len = strlen(extensions[i].ext);
+ if( !strncmp(&buffer[buflen-len], extensions[i].ext, len)) {
+ fstr =extensions[i].filetype;
+ break;
+ }
+ }
+ if(fstr == 0) logger(FORBIDDEN,"file extension type not supported",buffer,fd);
+
+ if(( file_fd = open(&buffer[5],O_RDONLY)) == -1) { /* open the file for reading */
+ logger(NOTFOUND, "failed to open file",&buffer[5],fd);
+ }
+ logger(LOG,"SEND",&buffer[5],hit);
+ len = (long)lseek(file_fd, (off_t)0, SEEK_END); /* lseek to the file end to find the length */
+ (void)lseek(file_fd, (off_t)0, SEEK_SET); /* lseek back to the file start ready for reading */
+ (void)sprintf(buffer,"HTTP/1.1 200 OK\nServer: ittpd/%d.0\nContent-Length: %ld\nConnection: close\nContent-Type: %s\n\n", VERSION, len, fstr); /* Header + a blank line */
+ logger(LOG,"Header",buffer,hit);
+ (void)write(fd,buffer,strlen(buffer));
+
+ /* send file in 8KB block - last block may be smaller */
+ while ( (ret = read(file_fd, buffer, BUFSIZE)) > 0 ) {
+ (void)write(fd,buffer,ret);
+ }
+ sleep(1); /* allow socket to drain before signalling the socket is closed */
+ close(fd);
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ int i, port, pid, listenfd, socketfd, hit;
+ socklen_t length;
+ static struct sockaddr_in cli_addr; /* static = initialised to zeros */
+ static struct sockaddr_in serv_addr; /* static = initialised to zeros */
+
+ if( argc < 3 || argc > 3 || !strcmp(argv[1], "-?") ) {
+ (void)printf("hint: ittpd Port-Number Top-Directory\t\tversion %d\n\n"
+ "ittpd is a very small web server\n"
+ "\n"
+ "example: ittpd 8181 /server/website\n"
+ );
+ exit(0);
+ }
+ if( !strncmp(argv[2],"/" ,2 ) || !strncmp(argv[2],"/etc", 5 ) ||
+ !strncmp(argv[2],"/bin",5 ) || !strncmp(argv[2],"/lib", 5 ) ||
+ !strncmp(argv[2],"/tmp",5 ) || !strncmp(argv[2],"/usr", 5 ) ||
+ !strncmp(argv[2],"/dev",5 ) || !strncmp(argv[2],"/sbin",6) ){
+ (void)printf("ERROR: Bad top directory %s, see ittpd -?\n",argv[2]);
+ exit(3);
+ }
+ if(chdir(argv[2]) == -1){
+ (void)printf("ERROR: Can't Change to directory %s\n",argv[2]);
+ exit(4);
+ }
+ /* Become deamon + unstopable and no zombies children (= no wait()) */
+ if(fork() != 0)
+ return 0; /* parent returns OK to shell */
+ (void)signal(SIGCHLD, SIG_IGN); /* ignore child death */
+ (void)signal(SIGHUP, SIG_IGN); /* ignore terminal hangups */
+ for(i=0;i<32;i++)
+ (void)close(i); /* close open files */
+ (void)setpgrp(); /* break away from process group */
+ logger(LOG,"ittpd starting",argv[1],getpid());
+ /* setup the network socket */
+ if((listenfd = socket(AF_INET, SOCK_STREAM,0)) <0)
+ logger(ERROR, "system call","socket",0);
+ port = atoi(argv[1]);
+ if(port < 0 || port >60000)
+ logger(ERROR,"Invalid port number (try 1->60000)",argv[1],0);
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ serv_addr.sin_port = htons(port);
+ if(bind(listenfd, (struct sockaddr *)&serv_addr,sizeof(serv_addr)) <0)
+ logger(ERROR,"system call","bind",0);
+ if( listen(listenfd,64) <0)
+ logger(ERROR,"system call","listen",0);
+ for(hit=1; ;hit++) {
+ length = sizeof(cli_addr);
+ if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0)
+ logger(ERROR,"system call","accept",0);
+ if((pid = fork()) < 0) {
+ logger(ERROR,"system call","fork",0);
+ }
+ else {
+ if(pid == 0) { /* child */
+ (void)close(listenfd);
+ web(socketfd,hit); /* never returns */
+ } else { /* parent */
+ (void)close(socketfd);
+ }
+ }
+ }
+} \ No newline at end of file